From 6c7266bb38cf6c3988c3ee31dcf20e6616fb1957 Mon Sep 17 00:00:00 2001 From: Zeev Belinsky Date: Tue, 23 Jun 2026 12:35:16 -0700 Subject: [PATCH] coproc/vecaccess/mxaccess/lxaccess: extend test suite and refactor Add comprehensive unit tests for mxaccess and lxaccess (previously untested), and replace the vecaccess smoke test with a full path-testing suite. All three tests share the same structure: unit_init with state verification, acquire/release/reuse bounded by a hardware-queried limit, a limit+1 blocking acquire via a second thread, double-release rejection, and a legacy-wrapper check. The tests derive the context limit by calling unit_init first (which latches the hardware style), then using h2_coproc_count() sign to mirror the impl's semaphore init logic for both oldstyle and newstyle hardware. Refactors in the implementation: - h2_coproc_init: fix one-shot regression (re-report OLDSTYLE on every call once latched; set init_done only after the full unit loop succeeds); add h2_coproc_init_result_t enum replacing magic 0/1/-1 - h2_coproc_set: replace per-call bit-scan with O(1) bitpos table lookup built at init time; remove redundant Q6_R_popcount_P call (use pre-computed counts[] array); remove dead `bits` local - h2_coproc: extract coproc_grow() helper, eliminating repeated realloc-assign-null-check pattern across init_entry_contexts and h2_coproc_init - h2_vecaccess/mxaccess/lxaccess release: add double-release guard (check active bit before releasing); fix idx passed to h2_coproc_set (was hardcoded 0); remove redundant h2_hwconfig_extbits call in vecaccess release - h2_vecaccess new-style branch: add missing HVX_64 case; align SILVER/SILVER_MAX sem init to use h2_coproc_count (was h2_info) - h2_vecaccess.h: add H2_VECACCESS_MAX_VLENGTH_BYTES replacing bare 128 Signed-off-by: Zeev Belinsky --- libs/h2_compat/coproc/h2_coproc.h | 10 +- libs/h2_compat/coproc/h2_coproc.ref.c | 133 +++++------ libs/h2_compat/lxaccess/h2_lxaccess.ref.c | 14 +- libs/h2_compat/lxaccess/test/Makefile | 8 + libs/h2_compat/lxaccess/test/Makefile.inc | 5 + libs/h2_compat/lxaccess/test/test.c | 201 ++++++++++++++++ libs/h2_compat/mxaccess/h2_mxaccess.ref.c | 12 +- libs/h2_compat/mxaccess/test/Makefile | 8 + libs/h2_compat/mxaccess/test/Makefile.inc | 5 + libs/h2_compat/mxaccess/test/test.c | 184 +++++++++++++++ libs/h2_compat/vecaccess/h2_vecaccess.h | 3 + libs/h2_compat/vecaccess/h2_vecaccess.ref.c | 26 +- libs/h2_compat/vecaccess/test/test.c | 248 ++++++++++++++++++-- scripts/testlist.v61 | 3 + 14 files changed, 757 insertions(+), 103 deletions(-) create mode 100644 libs/h2_compat/lxaccess/test/Makefile create mode 100644 libs/h2_compat/lxaccess/test/Makefile.inc create mode 100644 libs/h2_compat/lxaccess/test/test.c create mode 100644 libs/h2_compat/mxaccess/test/Makefile create mode 100644 libs/h2_compat/mxaccess/test/Makefile.inc create mode 100644 libs/h2_compat/mxaccess/test/test.c diff --git a/libs/h2_compat/coproc/h2_coproc.h b/libs/h2_compat/coproc/h2_coproc.h index 8ea63a206..9ab3ea605 100644 --- a/libs/h2_compat/coproc/h2_coproc.h +++ b/libs/h2_compat/coproc/h2_coproc.h @@ -41,12 +41,18 @@ Count coprocessor (context) instances */ int h2_coproc_set(h2_coproc_type_t type, h2_coproc_subtype_t subtype, h2_cfg_unit_entry entry_type, unsigned int unit_mask, unsigned int num, unsigned int enable); +typedef enum { + H2_COPROC_INIT_OK = 0, + H2_COPROC_INIT_OLDSTYLE = 1, + H2_COPROC_INIT_ERROR = -1, +} h2_coproc_init_result_t; + /** Initialize coprocessor data -@returns 0 on success; 1 to indicate absence of multi-unit configuration; -1 on error +@returns H2_COPROC_INIT_OK on success; H2_COPROC_INIT_OLDSTYLE if multi-unit configuration is absent; H2_COPROC_INIT_ERROR on error @dependencies None */ -int h2_coproc_init(); +h2_coproc_init_result_t h2_coproc_init(); /** @} */ diff --git a/libs/h2_compat/coproc/h2_coproc.ref.c b/libs/h2_compat/coproc/h2_coproc.ref.c index d37b08447..e7f0b2955 100644 --- a/libs/h2_compat/coproc/h2_coproc.ref.c +++ b/libs/h2_compat/coproc/h2_coproc.ref.c @@ -6,12 +6,40 @@ #include #include +/* Number of context bits in a unit's context mask (one unsigned int). */ +#define COPROC_BITS_PER_UNIT (sizeof(unsigned int) * 8) + static unsigned int *configs[CFG_TYPE_MAX][CFG_SUBTYPE_MAX] = {NULL}; static unsigned int nunits[CFG_TYPE_MAX][CFG_SUBTYPE_MAX] = {0}; static unsigned int *counts[CFG_TYPE_MAX][CFG_SUBTYPE_MAX][CFG_MAX] = {NULL}; +static unsigned char *bitpos[CFG_TYPE_MAX][CFG_SUBTYPE_MAX][CFG_MAX] = {NULL}; static unsigned int oldstyle = 0; static unsigned int init_done = 0; +/* Record the bit positions of the set bits in `bits`, in ascending order, into `out`. */ +static void coproc_build_bitpos(unsigned int bits, unsigned char *out) { + unsigned int pos = 0; + unsigned int k = 0; + + while (bits) { + if (bits & 0x1) { + out[k++] = (unsigned char)pos; + } + bits >>= 1; + pos++; + } +} + +static int coproc_grow(void **slot, int newsize) { + void *p = h2_realloc(*slot, newsize); + + if (NULL == p) { + return -1; + } + *slot = p; + return 0; +} + int h2_coproc_count(h2_coproc_type_t type, h2_coproc_subtype_t subtype, h2_cfg_unit_entry entry_type, unsigned int unit_mask) { unsigned int i; int ret = 0; @@ -63,39 +91,22 @@ int h2_coproc_set(h2_coproc_type_t type, h2_coproc_subtype_t subtype, h2_cfg_uni unsigned int idx = 0; // unit being considered unsigned int ncontexts; - unsigned int bits; unsigned int xa; unsigned int *entry; if (oldstyle || !enable) { - return setbits(type, subtype, entry_type, num, enable); // + return setbits(type, subtype, entry_type, num, enable); } num += 1; // num == number of existing contexts left to find - + while (num && idx < nunits[type][subtype]) { // still searching and in range if (unit_mask & (0x1 << idx)) { // unit selected entry = &configs[type][subtype][idx * CFG_MAX]; - bits = entry[entry_type]; - ncontexts = Q6_R_popcount_P(bits); + ncontexts = counts[type][subtype][entry_type][idx]; if (num <= ncontexts) { // requested context # is in this unit - xa = 0; // index of bit - do { - if (bits & 0x1) { // context exists - if (0 == (--num)) { // none left to find; now xa is correct - break; - } else { - xa++; - continue; - } - } else { // context is missing - bits >>= 1; // check next bit - xa++; - continue; - } - } while (1); - - // now xa is the index of the bit in the current unit that corresponds to the requested context # + xa = bitpos[type][subtype][entry_type][idx * COPROC_BITS_PER_UNIT + (num - 1)]; + setbits(type, subtype, entry_type, xa, enable); h2_hwconfig_set_coprocbits(entry[CFG_VXU_UNIT_ID]); // FIXME: need to get the ID field for this unit type return 0; @@ -109,6 +120,25 @@ int h2_coproc_set(h2_coproc_type_t type, h2_coproc_subtype_t subtype, h2_cfg_uni return -1; } +/* + * Populate the per-unit context count and logical->physical bit map for one + * entry type (HVX/HLX/HMX) of a unit. Grows the count array to cover `idx` + * and the bitpos array to cover this unit's COPROC_BITS_PER_UNIT slot. + */ +static int init_entry_contexts(h2_coproc_type_t type, h2_coproc_subtype_t subtype, h2_cfg_unit_entry entry_type, unsigned int idx, unsigned int bits) { + if (-1 == coproc_grow((void **)&counts[type][subtype][entry_type], (idx + 1) * sizeof(unsigned int))) { + return -1; + } + counts[type][subtype][entry_type][idx] = Q6_R_popcount_P(bits); + + if (-1 == coproc_grow((void **)&bitpos[type][subtype][entry_type], (idx + 1) * COPROC_BITS_PER_UNIT * sizeof(unsigned char))) { + return -1; + } + coproc_build_bitpos(bits, &bitpos[type][subtype][entry_type][idx * COPROC_BITS_PER_UNIT]); + + return 0; +} + static int init_entry_vxu0(unsigned int unit, h2_coproc_type_t type, h2_coproc_subtype_t subtype, unsigned int idx) { unsigned int *entry; @@ -116,26 +146,20 @@ static int init_entry_vxu0(unsigned int unit, h2_coproc_type_t type, h2_coproc_s entry[CFG_VXU_UNIT_ID] = h2_info_unit(unit, CFG_VXU_UNIT_ID); entry[CFG_HVX_CONTEXTS] = h2_info_unit(unit, CFG_HVX_CONTEXTS); - if (NULL == (counts[type][subtype][CFG_HVX_CONTEXTS] = - h2_realloc(counts[type][subtype][CFG_HVX_CONTEXTS], (idx + 1) * sizeof(unsigned int)))) { + if (-1 == init_entry_contexts(type, subtype, CFG_HVX_CONTEXTS, idx, entry[CFG_HVX_CONTEXTS])) { return -1; } - counts[type][subtype][CFG_HVX_CONTEXTS][idx] = Q6_R_popcount_P(entry[CFG_HVX_CONTEXTS]); - + entry[CFG_HLX_CONTEXTS] = h2_info_unit(unit, CFG_HLX_CONTEXTS); - if (NULL == (counts[type][subtype][CFG_HLX_CONTEXTS] = - h2_realloc(counts[type][subtype][CFG_HLX_CONTEXTS], (idx + 1) * sizeof(unsigned int)))) { + if (-1 == init_entry_contexts(type, subtype, CFG_HLX_CONTEXTS, idx, entry[CFG_HLX_CONTEXTS])) { return -1; } - counts[type][subtype][CFG_HLX_CONTEXTS][idx] = Q6_R_popcount_P(entry[CFG_HLX_CONTEXTS]); - + entry[CFG_HMX_CONTEXTS] = h2_info_unit(unit, CFG_HMX_CONTEXTS); - if (NULL == (counts[type][subtype][CFG_HMX_CONTEXTS] = - h2_realloc(counts[type][subtype][CFG_HMX_CONTEXTS], (idx + 1) * sizeof(unsigned int)))) { + if (-1 == init_entry_contexts(type, subtype, CFG_HMX_CONTEXTS, idx, entry[CFG_HMX_CONTEXTS])) { return -1; } - counts[type][subtype][CFG_HMX_CONTEXTS][idx] = Q6_R_popcount_P(entry[CFG_HMX_CONTEXTS]); - + return 0; } @@ -147,58 +171,35 @@ static const initptr_t inits[CFG_TYPE_MAX][CFG_SUBTYPE_MAX] = { } }; -int h2_coproc_init() { +h2_coproc_init_result_t h2_coproc_init() { unsigned int unit; h2_coproc_type_t type; h2_coproc_subtype_t subtype; unsigned int idx; if (init_done) { - return 0; + return oldstyle ? H2_COPROC_INIT_OLDSTYLE : H2_COPROC_INIT_OK; } - + if (0 == (unit = h2_info(INFO_UNIT_START))) { // old style oldstyle = 1; init_done = 1; - return 1; + return H2_COPROC_INIT_OLDSTYLE; } - init_done = 1; while (unit) { type = h2_info_unit(unit, CFG_UNIT_ID); subtype = h2_info_unit(unit, CFG_UNIT_SUBID); idx = nunits[type][subtype]; - if (NULL == (configs[type][subtype] = - h2_realloc(configs[type][subtype], CFG_MAX * (idx + 1) * sizeof(unsigned int)))) { - return -1; + if (-1 == coproc_grow((void **)&configs[type][subtype], CFG_MAX * (idx + 1) * sizeof(unsigned int))) { + return H2_COPROC_INIT_ERROR; } nunits[type][subtype]++; - if (-1 == inits[type][subtype](unit, type, subtype, idx)) return -1; + if (-1 == inits[type][subtype](unit, type, subtype, idx)) return H2_COPROC_INIT_ERROR; unit = h2_info_unit(unit, CFG_UNIT_NEXT); } - /* printf ("nunits 0x%08x\n", nunits[0][0]); */ - - /* printf ("unit ID 0x%08x\n", configs[0][0][CFG_VXU_UNIT_ID]); */ - - /* printf ("configs 0x%08x\n", configs[0][0][CFG_HVX_CONTEXTS]); */ - /* printf ("configs 0x%08x\n", configs[0][0][CFG_HLX_CONTEXTS]); */ - /* printf ("configs 0x%08x\n", configs[0][0][CFG_HMX_CONTEXTS]); */ - - /* printf ("counts 0x%08x\n", counts[0][0][CFG_HVX_CONTEXTS][0]); */ - /* printf ("counts 0x%08x\n", counts[0][0][CFG_HLX_CONTEXTS][0]); */ - /* printf ("counts 0x%08x\n", counts[0][0][CFG_HMX_CONTEXTS][0]); */ - - /* printf ("unit ID 0x%08x\n", configs[0][0][CFG_MAX + CFG_VXU_UNIT_ID]); */ - - /* printf ("configs 0x%08x\n", configs[0][0][CFG_MAX + CFG_HVX_CONTEXTS]); */ - /* printf ("configs 0x%08x\n", configs[0][0][CFG_MAX + CFG_HLX_CONTEXTS]); */ - /* printf ("configs 0x%08x\n", configs[0][0][CFG_MAX + CFG_HMX_CONTEXTS]); */ - - /* printf ("counts 0x%08x\n", counts[0][0][CFG_HVX_CONTEXTS][1]); */ - /* printf ("counts 0x%08x\n", counts[0][0][CFG_HLX_CONTEXTS][1]); */ - /* printf ("counts 0x%08x\n", counts[0][0][CFG_HMX_CONTEXTS][1]); */ - - return 0; + init_done = 1; + return H2_COPROC_INIT_OK; } diff --git a/libs/h2_compat/lxaccess/h2_lxaccess.ref.c b/libs/h2_compat/lxaccess/h2_lxaccess.ref.c index d9c03629f..7ccec1535 100644 --- a/libs/h2_compat/lxaccess/h2_lxaccess.ref.c +++ b/libs/h2_compat/lxaccess/h2_lxaccess.ref.c @@ -11,11 +11,11 @@ int h2_lxaccess_unit_init(h2_lxaccess_state_t *lxacc, h2_coproc_type_t type, h2_coproc_subtype_t subtype, h2_cfg_unit_entry entry_type, unsigned int unit_mask) { #ifdef HMX_HLX_SUPPORT - int ret; - + h2_coproc_init_result_t ret; + if ((ret = h2_coproc_init()) < 0) return ret; - if (1 == ret) { // old style + if (H2_COPROC_INIT_OLDSTYLE == ret) { // old style h2_sem_init_val(&lxacc->sem, h2_info(INFO_HLX_CONTEXTS)); } else { h2_sem_init_val(&lxacc->sem, h2_coproc_count(type, subtype, entry_type, unit_mask)); @@ -63,12 +63,16 @@ int h2_lxaccess_acquire(h2_lxaccess_state_t *lxacc) { #endif } -int h2_lxaccess_release(h2_lxaccess_state_t *lxacc, int idx) +int h2_lxaccess_release(h2_lxaccess_state_t *lxacc, int idx) { #ifdef HMX_HLX_SUPPORT int ret; - ret = h2_coproc_set(lxacc->type, lxacc->subtype, lxacc->entry_type, lxacc->unit_mask, 0, 0); + if (!(lxacc->active & (1u << idx))) { + return -1; + } + + ret = h2_coproc_set(lxacc->type, lxacc->subtype, lxacc->entry_type, lxacc->unit_mask, idx, 0); h2_atomic_clrbit32(&lxacc->active, idx); h2_sem_up(&lxacc->sem); diff --git a/libs/h2_compat/lxaccess/test/Makefile b/libs/h2_compat/lxaccess/test/Makefile new file mode 100644 index 000000000..271326574 --- /dev/null +++ b/libs/h2_compat/lxaccess/test/Makefile @@ -0,0 +1,8 @@ +#Hey emacs this is a -*- Makefile -*- +BOOT=1 +OBJS+=test.o +EXEC=test.elf + +include Makefile.inc + +CFLAGS += -v -G0 diff --git a/libs/h2_compat/lxaccess/test/Makefile.inc b/libs/h2_compat/lxaccess/test/Makefile.inc new file mode 100644 index 000000000..8aa91d777 --- /dev/null +++ b/libs/h2_compat/lxaccess/test/Makefile.inc @@ -0,0 +1,5 @@ +# Hey emacs this is a -*- Makefile -*- + +H2DIR=${UPDIR}../../../.. + +include ${H2DIR}/scripts/Makefile.inc.test diff --git a/libs/h2_compat/lxaccess/test/test.c b/libs/h2_compat/lxaccess/test/test.c new file mode 100644 index 000000000..8af42414c --- /dev/null +++ b/libs/h2_compat/lxaccess/test/test.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause-Clear + */ + +/* + * HLX Access (lxaccess) unit test. + * + * The context limit is seeded from h2_info(INFO_HLX_CONTEXTS). + * On hardware where HLX is absent the limit will be 0 and the test + * verifies the graceful absent-hardware path (all calls return -1). + */ + +#include +#include +#include +#include + +#define HELPER_STACK 256 + +static unsigned long long int helper_stack[HELPER_STACK]; + +void FAIL(const char *str) +{ + puts("FAIL"); + h2_printf(str); + exit(1); +} + +static void acquire_n(h2_lxaccess_state_t *lxacc, int *ret, int n, int limit) +{ + unsigned int seen = 0; + int i; + + for (i = 0; i < n; i++) { + ret[i] = h2_lxaccess_acquire(lxacc); + if (ret[i] < 0 || ret[i] >= limit) { + FAIL("acquire returned an out-of-range index\n"); + } + if (seen & (1u << ret[i])) { + FAIL("acquire returned a duplicate index\n"); + } + seen |= (1u << ret[i]); + } +} + +static void release_n(h2_lxaccess_state_t *lxacc, int *ret, int n) +{ + int i; + + for (i = 0; i < n; i++) { + if (h2_lxaccess_release(lxacc, ret[i]) != 0) { + FAIL("release failed\n"); + } + } +} + +typedef struct { + h2_lxaccess_state_t *lxacc; + h2_sem_t *ready; + h2_sem_t *done; + int *ret; + int limit; +} blocker_args_t; + +void blocker(int thread) +{ + blocker_args_t *a = (blocker_args_t *)(void *)(unsigned int)thread; + + h2_sem_up(a->ready); + acquire_n(a->lxacc, a->ret, 1, a->limit); + h2_sem_up(a->done); + h2_thread_stop(0); +} + +int main() +{ + h2_lxaccess_state_t lxacc; + int ret[33]; + int blocker_ret; + h2_sem_t ready, done; + blocker_args_t args; + const h2_coproc_type_t init_type = CFG_TYPE_VXU0; + const h2_coproc_subtype_t init_subtype = CFG_SUBTYPE_VXU0; + const h2_cfg_unit_entry init_entry_type = CFG_HLX_CONTEXTS; + const unsigned int init_unit_mask = 0x1; + int limit; + int i; + + /* --- 1. unit_init and derive limit ----------------------------------- */ + if (h2_lxaccess_unit_init(&lxacc, init_type, init_subtype, + init_entry_type, init_unit_mask) != 0) { + FAIL("unit_init failed\n"); + } + { + int count = h2_coproc_count(init_type, init_subtype, init_entry_type, init_unit_mask); + limit = (count < 0) ? h2_info(INFO_HLX_CONTEXTS) : count; + } + printf("limit %d\n", limit); + + if (limit == 0) { + /* HLX not present: semaphore is non-acquirable. */ + if (h2_sem_trydown(&lxacc.sem) == 0) { + FAIL("sem should not be acquirable with no HLX contexts\n"); + } + if (h2_lxaccess_init(&lxacc) != 0) { + FAIL("legacy init failed unexpectedly\n"); + } + printf("SKIP: HLX not present on this hardware\n"); + printf("TEST PASSED\n"); + h2_thread_stop(0); + return 0; + } + + if (lxacc.active != 0) { + FAIL("unit_init did not clear active\n"); + } + if (lxacc.type != init_type) { + FAIL("unit_init set wrong type\n"); + } + if (lxacc.subtype != init_subtype) { + FAIL("unit_init set wrong subtype\n"); + } + if (lxacc.entry_type != init_entry_type) { + FAIL("unit_init set wrong entry_type\n"); + } + if (lxacc.unit_mask != init_unit_mask) { + FAIL("unit_init set wrong unit_mask\n"); + } + if (limit > (int)(sizeof(ret) / sizeof(ret[0]) - 1)) { + FAIL("seeded limit is out of range\n"); + } + printf("PASS: unit_init\n"); + + /* --- 2. acquire / release / reuse ------------------------------------ */ + acquire_n(&lxacc, ret, limit, limit); + release_n(&lxacc, ret, limit); + + acquire_n(&lxacc, ret, limit, limit); + printf("PASS: acquire/release/reuse up to limit=%d\n", limit); + + /* --- 3. limit+1 acquire blocks; wakes when a slot is freed ----------- */ + blocker_ret = -1; + args.lxacc = &lxacc; + args.ready = &ready; + args.done = &done; + args.ret = &blocker_ret; + args.limit = limit; + h2_sem_init_val(&ready, 0); + h2_sem_init_val(&done, 0); + + h2_thread_create(blocker, &helper_stack[HELPER_STACK], + (void *)&args, h2_get_prio(pthread_self())); + h2_sem_down(&ready); + + if (h2_lxaccess_release(&lxacc, ret[0]) != 0) { + FAIL("release in blocking test failed\n"); + } + h2_sem_down(&done); + + if (h2_lxaccess_release(&lxacc, blocker_ret) != 0) { + FAIL("release of blocker slot failed\n"); + } + for (i = 1; i < limit; i++) { + if (h2_lxaccess_release(&lxacc, ret[i]) != 0) { + FAIL("cleanup release failed\n"); + } + } + printf("PASS: limit+1 acquire blocked and woke on release\n"); + + /* --- 4. Double-release is rejected ---------------------------------- */ + acquire_n(&lxacc, ret, 1, limit); + if (h2_lxaccess_release(&lxacc, ret[0]) != 0) { + FAIL("first release failed\n"); + } + if (h2_lxaccess_release(&lxacc, ret[0]) != -1) { + FAIL("double-release was not rejected\n"); + } + for (i = 0; i < limit; i++) { + if (h2_sem_trydown(&lxacc.sem) != 0) { + FAIL("semaphore under-counts after double-release guard\n"); + } + } + if (h2_sem_trydown(&lxacc.sem) == 0) { + FAIL("semaphore over-counts -- double-release guard did not work\n"); + } + for (i = 0; i < limit; i++) { + h2_sem_up(&lxacc.sem); + } + printf("PASS: double-release correctly rejected\n"); + + /* --- 5. Legacy wrapper ----------------------------------------------- */ + if (h2_lxaccess_init(&lxacc) != 0) { + FAIL("legacy h2_lxaccess_init failed\n"); + } + printf("PASS: legacy lxaccess_init\n"); + + printf("TEST PASSED\n"); + h2_thread_stop(0); + return 0; +} diff --git a/libs/h2_compat/mxaccess/h2_mxaccess.ref.c b/libs/h2_compat/mxaccess/h2_mxaccess.ref.c index a633a5aad..ffacef118 100644 --- a/libs/h2_compat/mxaccess/h2_mxaccess.ref.c +++ b/libs/h2_compat/mxaccess/h2_mxaccess.ref.c @@ -11,11 +11,11 @@ int h2_mxaccess_unit_init(h2_mxaccess_state_t *mxacc, h2_coproc_type_t type, h2_coproc_subtype_t subtype, h2_cfg_unit_entry entry_type, unsigned int unit_mask) { #ifdef HMX_HLX_SUPPORT - int ret; + h2_coproc_init_result_t ret; if ((ret = h2_coproc_init()) < 0) return ret; - if (1 == ret) { // old style + if (H2_COPROC_INIT_OLDSTYLE == ret) { // old style h2_sem_init_val(&mxacc->sem, h2_info(INFO_HMX_INSTANCES)); } else { h2_sem_init_val(&mxacc->sem, h2_coproc_count(type, subtype, entry_type, unit_mask)); @@ -61,12 +61,16 @@ int h2_mxaccess_acquire(h2_mxaccess_state_t *mxacc) { #endif } -int h2_mxaccess_release(h2_mxaccess_state_t *mxacc, int idx) +int h2_mxaccess_release(h2_mxaccess_state_t *mxacc, int idx) { #ifdef HMX_HLX_SUPPORT int ret; - ret = h2_coproc_set(mxacc->type, mxacc->subtype, mxacc->entry_type, mxacc->unit_mask, 0, 0); + if (!(mxacc->active & (1u << idx))) { + return -1; + } + + ret = h2_coproc_set(mxacc->type, mxacc->subtype, mxacc->entry_type, mxacc->unit_mask, idx, 0); h2_atomic_clrbit32(&mxacc->active, idx); h2_sem_up(&mxacc->sem); diff --git a/libs/h2_compat/mxaccess/test/Makefile b/libs/h2_compat/mxaccess/test/Makefile new file mode 100644 index 000000000..271326574 --- /dev/null +++ b/libs/h2_compat/mxaccess/test/Makefile @@ -0,0 +1,8 @@ +#Hey emacs this is a -*- Makefile -*- +BOOT=1 +OBJS+=test.o +EXEC=test.elf + +include Makefile.inc + +CFLAGS += -v -G0 diff --git a/libs/h2_compat/mxaccess/test/Makefile.inc b/libs/h2_compat/mxaccess/test/Makefile.inc new file mode 100644 index 000000000..8aa91d777 --- /dev/null +++ b/libs/h2_compat/mxaccess/test/Makefile.inc @@ -0,0 +1,5 @@ +# Hey emacs this is a -*- Makefile -*- + +H2DIR=${UPDIR}../../../.. + +include ${H2DIR}/scripts/Makefile.inc.test diff --git a/libs/h2_compat/mxaccess/test/test.c b/libs/h2_compat/mxaccess/test/test.c new file mode 100644 index 000000000..a23d5dd38 --- /dev/null +++ b/libs/h2_compat/mxaccess/test/test.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause-Clear + */ + +/* + * HMX Access (mxaccess) unit test. + * + * The context limit is seeded from h2_info(INFO_HMX_INSTANCES). + */ + +#include +#include +#include +#include + +#define HELPER_STACK 256 + +static unsigned long long int helper_stack[HELPER_STACK]; + +void FAIL(const char *str) +{ + puts("FAIL"); + h2_printf(str); + exit(1); +} + +static void acquire_n(h2_mxaccess_state_t *mxacc, int *ret, int n, int limit) +{ + unsigned int seen = 0; + int i; + + for (i = 0; i < n; i++) { + ret[i] = h2_mxaccess_acquire(mxacc); + if (ret[i] < 0 || ret[i] >= limit) { + FAIL("acquire returned an out-of-range index\n"); + } + if (seen & (1u << ret[i])) { + FAIL("acquire returned a duplicate index\n"); + } + seen |= (1u << ret[i]); + } +} + +static void release_n(h2_mxaccess_state_t *mxacc, int *ret, int n) +{ + int i; + + for (i = 0; i < n; i++) { + if (h2_mxaccess_release(mxacc, ret[i]) != 0) { + FAIL("release failed\n"); + } + } +} + +typedef struct { + h2_mxaccess_state_t *mxacc; + h2_sem_t *ready; + h2_sem_t *done; + int *ret; + int limit; +} blocker_args_t; + +void blocker(int thread) +{ + blocker_args_t *a = (blocker_args_t *)(void *)(unsigned int)thread; + + h2_sem_up(a->ready); + acquire_n(a->mxacc, a->ret, 1, a->limit); + h2_sem_up(a->done); + h2_thread_stop(0); +} + +int main() +{ + h2_mxaccess_state_t mxacc; + int ret[33]; + int blocker_ret; + h2_sem_t ready, done; + blocker_args_t args; + const h2_coproc_type_t init_type = CFG_TYPE_VXU0; + const h2_coproc_subtype_t init_subtype = CFG_SUBTYPE_VXU0; + const h2_cfg_unit_entry init_entry_type = CFG_HMX_CONTEXTS; + const unsigned int init_unit_mask = 0x1; + int limit; + int i; + + /* --- 1. unit_init and derive limit ----------------------------------- */ + if (h2_mxaccess_unit_init(&mxacc, init_type, init_subtype, + init_entry_type, init_unit_mask) != 0) { + FAIL("unit_init failed\n"); + } + if (mxacc.active != 0) { + FAIL("unit_init did not clear active\n"); + } + if (mxacc.type != init_type) { + FAIL("unit_init set wrong type\n"); + } + if (mxacc.subtype != init_subtype) { + FAIL("unit_init set wrong subtype\n"); + } + if (mxacc.entry_type != init_entry_type) { + FAIL("unit_init set wrong entry_type\n"); + } + if (mxacc.unit_mask != init_unit_mask) { + FAIL("unit_init set wrong unit_mask\n"); + } + { + int count = h2_coproc_count(init_type, init_subtype, init_entry_type, init_unit_mask); + limit = (count < 0) ? h2_info(INFO_HMX_INSTANCES) : count; + } + printf("limit %d\n", limit); + if (limit <= 0 || limit > (int)(sizeof(ret) / sizeof(ret[0]) - 1)) { + FAIL("seeded limit is out of range\n"); + } + printf("PASS: unit_init\n"); + + /* --- 2. acquire / release / reuse ------------------------------------ */ + acquire_n(&mxacc, ret, limit, limit); + release_n(&mxacc, ret, limit); + + acquire_n(&mxacc, ret, limit, limit); + printf("PASS: acquire/release/reuse up to limit=%d\n", limit); + + /* --- 3. limit+1 acquire blocks; wakes when a slot is freed ----------- */ + blocker_ret = -1; + args.mxacc = &mxacc; + args.ready = &ready; + args.done = &done; + args.ret = &blocker_ret; + args.limit = limit; + h2_sem_init_val(&ready, 0); + h2_sem_init_val(&done, 0); + + h2_thread_create(blocker, &helper_stack[HELPER_STACK], + (void *)&args, h2_get_prio(pthread_self())); + h2_sem_down(&ready); + + if (h2_mxaccess_release(&mxacc, ret[0]) != 0) { + FAIL("release in blocking test failed\n"); + } + h2_sem_down(&done); + + if (h2_mxaccess_release(&mxacc, blocker_ret) != 0) { + FAIL("release of blocker slot failed\n"); + } + for (i = 1; i < limit; i++) { + if (h2_mxaccess_release(&mxacc, ret[i]) != 0) { + FAIL("cleanup release failed\n"); + } + } + printf("PASS: limit+1 acquire blocked and woke on release\n"); + + /* --- 4. Double-release is rejected ---------------------------------- */ + acquire_n(&mxacc, ret, 1, limit); + if (h2_mxaccess_release(&mxacc, ret[0]) != 0) { + FAIL("first release failed\n"); + } + if (h2_mxaccess_release(&mxacc, ret[0]) != -1) { + FAIL("double-release was not rejected\n"); + } + for (i = 0; i < limit; i++) { + if (h2_sem_trydown(&mxacc.sem) != 0) { + FAIL("semaphore under-counts after double-release guard\n"); + } + } + if (h2_sem_trydown(&mxacc.sem) == 0) { + FAIL("semaphore over-counts -- double-release guard did not work\n"); + } + for (i = 0; i < limit; i++) { + h2_sem_up(&mxacc.sem); + } + printf("PASS: double-release correctly rejected\n"); + + /* --- 5. Legacy wrapper ----------------------------------------------- */ + if (h2_mxaccess_init(&mxacc) != 0) { + FAIL("legacy h2_mxaccess_init failed\n"); + } + printf("PASS: legacy mxaccess_init\n"); + + printf("TEST PASSED\n"); + h2_thread_stop(0); + return 0; +} diff --git a/libs/h2_compat/vecaccess/h2_vecaccess.h b/libs/h2_compat/vecaccess/h2_vecaccess.h index dd5b4f0a6..c31b9fc24 100644 --- a/libs/h2_compat/vecaccess/h2_vecaccess.h +++ b/libs/h2_compat/vecaccess/h2_vecaccess.h @@ -22,6 +22,9 @@ #define H2_VECACCESS_EXT_SILVER 0 #define H2_VECACCESS_EXT_HVX 0 +/* Maximum HVX vector length in bytes. */ +#define H2_VECACCESS_MAX_VLENGTH_BYTES 128 + enum { H2_VECACCESS_VLENGTH_MIN, H2_VECACCESS_VLENGTH_32 = 5, diff --git a/libs/h2_compat/vecaccess/h2_vecaccess.ref.c b/libs/h2_compat/vecaccess/h2_vecaccess.ref.c index 343e39635..5222cf422 100644 --- a/libs/h2_compat/vecaccess/h2_vecaccess.ref.c +++ b/libs/h2_compat/vecaccess/h2_vecaccess.ref.c @@ -10,14 +10,14 @@ #include "h2_vecaccess.h" int h2_vecaccess_unit_init(h2_vecaccess_state_t *vacc, unsigned int req, h2_coproc_type_t type, h2_coproc_subtype_t subtype, h2_cfg_unit_entry entry_type, unsigned int unit_mask) { - int ret; + h2_coproc_init_result_t ret; /* Block by default if init fails */ h2_sem_init_val(&vacc->sem, 0); if ((ret = h2_coproc_init()) < 0) return ret; - if (1 == ret) { // old style + if (H2_COPROC_INIT_OLDSTYLE == ret) { unsigned long native_vlength = h2_info(INFO_HVX_VLENGTH); @@ -42,20 +42,27 @@ int h2_vecaccess_unit_init(h2_vecaccess_state_t *vacc, unsigned int req, h2_copr if ((ret = h2_hwconfig_vlength(H2_VECACCESS_VLENGTH_128)) <0) return ret; vacc->ext = H2_VECACCESS_EXT_HVX; vacc->length = H2_VECACCESS_VLENGTH_128; - h2_sem_init_val(&vacc->sem, h2_info(INFO_COPROC_CONTEXTS) / (128 / native_vlength)); + h2_sem_init_val(&vacc->sem, h2_info(INFO_COPROC_CONTEXTS) / (H2_VECACCESS_MAX_VLENGTH_BYTES / native_vlength)); break; default: return -1; } } else { - switch(req) { // still old style + switch(req) { case H2_VECACCESS_SILVER: case H2_VECACCESS_SILVER_MAX: if ((ret = h2_hwconfig_vlength(H2_VECACCESS_VLENGTH_MIN)) <0) return ret; vacc->ext = H2_VECACCESS_EXT_SILVER; vacc->length = H2_VECACCESS_VLENGTH_128; - h2_sem_init_val(&vacc->sem, h2_info(INFO_COPROC_CONTEXTS)); + h2_sem_init_val(&vacc->sem, h2_coproc_count(type, subtype, entry_type, unit_mask)); + break; + + case H2_VECACCESS_HVX_64: + if ((ret = h2_hwconfig_vlength(H2_VECACCESS_VLENGTH_64)) <0) return ret; + vacc->ext = H2_VECACCESS_EXT_HVX; + vacc->length = H2_VECACCESS_VLENGTH_64; + h2_sem_init_val(&vacc->sem, h2_coproc_count(type, subtype, entry_type, unit_mask)); break; case H2_VECACCESS_HVX_128: @@ -113,10 +120,13 @@ h2_vecaccess_ret_t h2_vecaccess_acquire(h2_vecaccess_state_t *vacc) { int h2_vecaccess_release(h2_vecaccess_state_t *vacc, int idx) { int ret; + if (!(vacc->active & (1u << idx))) { + return -1; + } + /* TURN OFF VECTORS */ - ret = h2_hwconfig_extbits(0, 0); - ret = h2_coproc_set(vacc->type, vacc->subtype, vacc->entry_type, vacc->unit_mask, 0, 0); - h2_atomic_clrbit32(&vacc->active,idx); + ret = h2_coproc_set(vacc->type, vacc->subtype, vacc->entry_type, vacc->unit_mask, idx, 0); + h2_atomic_clrbit32(&vacc->active, idx); h2_sem_up(&vacc->sem); return ret; diff --git a/libs/h2_compat/vecaccess/test/test.c b/libs/h2_compat/vecaccess/test/test.c index ac1dd8659..92aa3468b 100644 --- a/libs/h2_compat/vecaccess/test/test.c +++ b/libs/h2_compat/vecaccess/test/test.c @@ -3,10 +3,24 @@ * SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Vector Access (vecaccess) unit test. + * + * The context limit is seeded from h2_info(INFO_COPROC_CONTEXTS) because there + * is no non-blocking vecaccess call to discover it: h2_vecaccess_acquire() + * blocks once all contexts are exhausted. + */ + #include #include +#include #include +#define GARBAGE_VALUE 0xFDA +#define HELPER_STACK 256 + +static unsigned long long int helper_stack[HELPER_STACK]; + void FAIL(const char *str) { puts("FAIL"); @@ -14,31 +28,229 @@ void FAIL(const char *str) exit(1); } -int main() { +static void acquire_n(h2_vecaccess_state_t *vacc, h2_vecaccess_ret_t *ret, + int n, int limit, int expect_length) +{ + unsigned int seen = 0; + int i; + + for (i = 0; i < n; i++) { + ret[i] = h2_vecaccess_acquire(vacc); + if (ret[i].idx < 0 || ret[i].idx >= limit) { + FAIL("acquire returned an out-of-range index\n"); + } + if (seen & (1u << ret[i].idx)) { + FAIL("acquire returned a duplicate index\n"); + } + seen |= (1u << ret[i].idx); + if (ret[i].length != expect_length) { + FAIL("acquire returned the wrong length\n"); + } + } +} + +static void release_n(h2_vecaccess_state_t *vacc, h2_vecaccess_ret_t *ret, int n) +{ + int i; + + for (i = 0; i < n; i++) { + if (h2_vecaccess_release(vacc, ret[i].idx) != 0) { + FAIL("release failed\n"); + } + } +} + + +typedef struct { + h2_vecaccess_state_t *vacc; + h2_sem_t *ready; + h2_sem_t *done; + h2_vecaccess_ret_t *ret; + int limit; + int length; +} blocker_args_t; +void blocker(int thread) +{ + blocker_args_t *a = (blocker_args_t *)(void *)(unsigned int)thread; + + h2_sem_up(a->ready); + /* This is the (limit+1)-th acquire -- blocks until main releases one. */ + acquire_n(a->vacc, a->ret, 1, a->limit, a->length); + h2_sem_up(a->done); + h2_thread_stop(0); +} + +int main() +{ h2_vecaccess_state_t vacc; - h2_vecaccess_ret_t ret; - unsigned int x; + h2_vecaccess_state_t block_vacc; + h2_vecaccess_ret_t ret[33]; /* limit slots for main + 1 for the blocker */ + h2_sem_t ready, done; + h2_vecaccess_ret_t blocker_ret; + blocker_args_t args; + unsigned long native_vlength; + const h2_coproc_type_t init_type = CFG_TYPE_VXU0; + const h2_coproc_subtype_t init_subtype = CFG_SUBTYPE_VXU0; + const h2_cfg_unit_entry init_entry_type = CFG_HVX_CONTEXTS; + const unsigned int init_unit_mask = 0x1; + int limit; + int length; + int i; + + /* --- 1. Seed the context limit from hardware ------------------------- */ + native_vlength = h2_info(INFO_HVX_VLENGTH); + if (native_vlength == 0) { + FAIL("INFO_HVX_VLENGTH is zero\n"); + } + limit = h2_info(INFO_COPROC_CONTEXTS) / (H2_VECACCESS_MAX_VLENGTH_BYTES / native_vlength); + printf("limit %d\n", limit); + if (limit <= 0 || limit > (int)(sizeof(ret) / sizeof(ret[0]))) { + FAIL("seeded limit is out of range\n"); + } + + /* --- 2. First unit_init; drives acquire tests ------------------------- */ + if (h2_vecaccess_unit_init(&block_vacc, H2_VECACCESS_HVX_128, + init_type, init_subtype, init_entry_type, init_unit_mask) != 0) { + FAIL("first unit_init (HVX_128) failed\n"); + } + if (block_vacc.length != H2_VECACCESS_VLENGTH_128) { + FAIL("HVX_128 set the wrong length\n"); + } + if (block_vacc.ext != H2_VECACCESS_EXT_HVX) { + FAIL("HVX_128 set the wrong ext\n"); + } + if (block_vacc.active != 0) { + FAIL("unit_init did not clear active\n"); + } + if (block_vacc.type != init_type) { + FAIL("unit_init set wrong type\n"); + } + if (block_vacc.subtype != init_subtype) { + FAIL("unit_init set wrong subtype\n"); + } + if (block_vacc.entry_type != init_entry_type) { + FAIL("unit_init set wrong entry_type\n"); + } + if (block_vacc.unit_mask != init_unit_mask) { + FAIL("unit_init set wrong unit_mask\n"); + } + length = block_vacc.length; + printf("PASS: first unit_init (HVX_128)\n"); - h2_vecaccess_unit_init(&vacc, H2_VECACCESS_HVX_128, CFG_TYPE_VXU0, CFG_SUBTYPE_VXU0, CFG_HVX_CONTEXTS, 0x1); - ret = h2_vecaccess_acquire(&vacc); - printf("ret.idx %d\n", ret.idx); - ret = h2_vecaccess_acquire(&vacc); - printf("ret.idx %d\n", ret.idx); - asm volatile ("%0 = ssr \n" : "=r"(x)); // crash + /* --- 3. acquire / release / reuse, bounded by the limit -------------- */ + acquire_n(&block_vacc, ret, limit, limit, length); + release_n(&block_vacc, ret, limit); - printf("HVX 0 %d\n", h2_coproc_count(CFG_TYPE_VXU0, CFG_SUBTYPE_VXU0, CFG_HVX_CONTEXTS, 0x1)); - printf("HVX 1 %d\n", h2_coproc_count(CFG_TYPE_VXU0, CFG_SUBTYPE_VXU0, CFG_HVX_CONTEXTS, 0x2)); - printf("HVX all %d\n", h2_coproc_count(CFG_TYPE_VXU0, CFG_SUBTYPE_VXU0, CFG_HVX_CONTEXTS, -1)); - printf("HVX none %d\n", h2_coproc_count(CFG_TYPE_VXU0, CFG_SUBTYPE_VXU0, CFG_HVX_CONTEXTS, 0x0)); + /* Re-acquire the full set to prove the released slots are reusable. */ + acquire_n(&block_vacc, ret, limit, limit, length); + printf("PASS: acquire/release/reuse up to limit=%d\n", limit); - printf("HMX 0 %d\n", h2_coproc_count(CFG_TYPE_VXU0, CFG_SUBTYPE_VXU0, CFG_HMX_CONTEXTS, 0x1)); - printf("HMX 1 %d\n", h2_coproc_count(CFG_TYPE_VXU0, CFG_SUBTYPE_VXU0, CFG_HMX_CONTEXTS, 0x2)); - printf("HMX all %d\n", h2_coproc_count(CFG_TYPE_VXU0, CFG_SUBTYPE_VXU0, CFG_HMX_CONTEXTS, -1)); + /* --- 4. limit+1 acquire blocks; wakes when a slot is freed ----------- */ + /* Main holds all `limit` slots (sem == 0). The blocker signals ready then + * calls acquire_n(..., 1), which is the (limit+1)-th acquire. Because the + * semaphore is at 0, the blocker will block in h2_sem_down regardless of + * scheduling order: if main releases first, sem goes 0->1 and the blocker + * drains it immediately; if the blocker reaches sem_down first, it blocks + * until main releases. Either way the test is correct. */ + blocker_ret.idx = -1; + args.vacc = &block_vacc; + args.ready = &ready; + args.done = &done; + args.ret = &blocker_ret; + args.limit = limit; + args.length = length; + h2_sem_init_val(&ready, 0); + h2_sem_init_val(&done, 0); - + h2_thread_create(blocker, &helper_stack[HELPER_STACK], + (void *)&args, h2_get_prio(pthread_self())); + h2_sem_down(&ready); /* wait until helper is about to block */ + + if (h2_vecaccess_release(&block_vacc, ret[0].idx) != 0) { + FAIL("release in blocking test failed\n"); + } + h2_sem_down(&done); /* blocker acquired; acquire_n validated idx/length */ + + /* Release the blocker's slot and the rest main still holds. */ + if (h2_vecaccess_release(&block_vacc, blocker_ret.idx) != 0) { + FAIL("release of blocker slot failed\n"); + } + for (i = 1; i < limit; i++) { + if (h2_vecaccess_release(&block_vacc, ret[i].idx) != 0) { + FAIL("cleanup release failed\n"); + } + } + printf("PASS: limit+1 acquire blocked and woke on release\n"); + + /* --- 5. Double-release is rejected ---------------------------------- */ + /* Acquire one slot, release it once (valid), then release again. The + * second release must fail (-1) because the bit is no longer set in + * active, and the semaphore must remain at limit (not be inflated). */ + acquire_n(&block_vacc, ret, 1, limit, length); /* sem: limit -> limit-1 */ + if (h2_vecaccess_release(&block_vacc, ret[0].idx) != 0) { + FAIL("first release failed\n"); + } + if (h2_vecaccess_release(&block_vacc, ret[0].idx) != -1) { + FAIL("double-release was not rejected\n"); + } + /* Semaphore must be exactly at limit (not inflated). */ + for (i = 0; i < limit; i++) { + if (h2_sem_trydown(&block_vacc.sem) != 0) { + FAIL("semaphore under-counts after double-release guard\n"); + } + } + if (h2_sem_trydown(&block_vacc.sem) == 0) { + FAIL("semaphore over-counts -- double-release guard did not work\n"); + } + /* Restore semaphore to limit. */ + for (i = 0; i < limit; i++) { + h2_sem_up(&block_vacc.sem); + } + printf("PASS: double-release correctly rejected\n"); + + /* --- 6. Request-path testing ---------------------------------------- */ + if (h2_vecaccess_unit_init(&vacc, H2_VECACCESS_SILVER, + init_type, init_subtype, init_entry_type, init_unit_mask) != 0 || + vacc.length != H2_VECACCESS_VLENGTH_128) { + FAIL("SILVER mapping wrong\n"); + } + if (h2_vecaccess_unit_init(&vacc, H2_VECACCESS_SILVER_MAX, + init_type, init_subtype, init_entry_type, init_unit_mask) != 0 || + vacc.length != H2_VECACCESS_VLENGTH_128) { + FAIL("SILVER_MAX mapping wrong\n"); + } + if (h2_vecaccess_unit_init(&vacc, H2_VECACCESS_HVX_64, + init_type, init_subtype, init_entry_type, init_unit_mask) != 0 || + vacc.length != H2_VECACCESS_VLENGTH_64) { + FAIL("HVX_64 mapping wrong\n"); + } + if (h2_vecaccess_unit_init(&vacc, H2_VECACCESS_HVX_128, + init_type, init_subtype, init_entry_type, init_unit_mask) != 0 || + vacc.length != H2_VECACCESS_VLENGTH_128) { + FAIL("HVX_128 mapping wrong\n"); + } + if (h2_vecaccess_unit_init(&vacc, H2_VECACCESS_HVX_MAX, + init_type, init_subtype, init_entry_type, init_unit_mask) != 0 || + vacc.length != H2_VECACCESS_VLENGTH_128) { + FAIL("HVX_MAX mapping wrong\n"); + } + if (h2_vecaccess_unit_init(&vacc, GARBAGE_VALUE, + init_type, init_subtype, init_entry_type, init_unit_mask) != -1) { + FAIL("invalid request was not rejected\n"); + } + printf("PASS: unit_init request paths\n"); + + /* --- 7. Legacy wrapper ----------------------------------------------- */ + if (h2_vecaccess_init(&vacc, H2_VECACCESS_HVX_128) != 0) { + FAIL("legacy h2_vecaccess_init failed\n"); + } + if (vacc.length != H2_VECACCESS_VLENGTH_128) { + FAIL("legacy init set wrong length\n"); + } + printf("PASS: legacy vecaccess_init\n"); printf("TEST PASSED\n"); + h2_thread_stop(0); return 0; } - diff --git a/scripts/testlist.v61 b/scripts/testlist.v61 index b489fe7cf..655195e45 100644 --- a/scripts/testlist.v61 +++ b/scripts/testlist.v61 @@ -90,6 +90,9 @@ ./libs/h2_compat/error/test/simple ./libs/h2_compat/sem/test/simple ./libs/h2_compat/sleep/test +./libs/h2_compat/vecaccess/test +./libs/h2_compat/mxaccess/test +./libs/h2_compat/lxaccess/test ./libs/h2/vmtraps/test/test_ie ./libs/h2/vmtraps/test/test_pcycles