summaryrefslogtreecommitdiff
path: root/hsspi_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'hsspi_test.c')
-rw-r--r--hsspi_test.c171
1 files changed, 171 insertions, 0 deletions
diff --git a/hsspi_test.c b/hsspi_test.c
new file mode 100644
index 0000000..598157e
--- /dev/null
+++ b/hsspi_test.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * This file is part of the QM35 UCI stack for linux.
+ *
+ * Copyright (c) 2021 Qorvo US, Inc.
+ *
+ * This software is provided under the GNU General Public License, version 2
+ * (GPLv2), as well as under a Qorvo commercial license.
+ *
+ * You may choose to use this software under the terms of the GPLv2 License,
+ * version 2 ("GPLv2"), as published by the Free Software Foundation.
+ * You should have received a copy of the GPLv2 along with this program. If
+ * not, see <http://www.gnu.org/licenses/>.
+ *
+ * This program is distributed under the GPLv2 in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GPLv2 for more
+ * details.
+ *
+ * If you cannot meet the requirements of the GPLv2, you may not use this
+ * software for any purpose without first obtaining a commercial license from
+ * Qorvo.
+ * Please contact Qorvo to inquire about licensing terms.
+ *
+ * QM35 UCI layer HSSPI Protocol
+ */
+
+#include "hsspi_test.h"
+#include "hsspi_uci.h"
+#include <linux/printk.h>
+#include <linux/delay.h>
+
+int hsspi_test_registered(struct hsspi_layer *upper_layer);
+void hsspi_test_unregistered(struct hsspi_layer *upper_layer);
+struct hsspi_block *hsspi_test_get(struct hsspi_layer *upper_layer, u16 length);
+void hsspi_test_received(struct hsspi_layer *upper_layer,
+ struct hsspi_block *blk, int status);
+void hsspi_test_sent(struct hsspi_layer *upper_layer,
+ struct hsspi_block *blk, int status);
+
+struct hsspi_layer_ops test_hsspi_layer_ops = {
+ .registered = hsspi_test_registered,
+ .unregistered = hsspi_test_unregistered,
+ .get = hsspi_test_get,
+ .received = hsspi_test_received,
+ .sent = hsspi_test_sent,
+};
+
+struct hsspi_layer test_hsspi_layer = {
+ .name = "hsspi_test_layer",
+ .id = UL_TEST_HSSPI,
+ .ops = &test_hsspi_layer_ops,
+};
+
+static struct hsspi *ghsspi;
+int sleep_inter_frame_ms;
+extern int test_sleep_after_ss_ready_us;
+
+int hsspi_test_init(struct hsspi *hsspi)
+{
+ ghsspi = hsspi;
+ return hsspi_register(hsspi, &test_hsspi_layer);
+}
+
+void hsspi_test_deinit(struct hsspi *hsspi)
+{
+ hsspi_unregister(hsspi, &test_hsspi_layer);
+}
+
+int hsspi_test_registered(struct hsspi_layer *upper_layer)
+{
+ return 0;
+}
+
+void hsspi_test_unregistered(struct hsspi_layer *upper_layer)
+{}
+
+static int check_rx(const u8 *rx, int len)
+{
+ int idx = 0, err = 0;
+ for ( ; idx < len ; idx++) {
+ if (rx[idx] != (idx & 0xff)) {
+ pr_err("hsspi test: check_rx rx[%u] != %u\n",
+ idx, rx[idx]);
+ print_hex_dump(KERN_DEBUG, "rx:", DUMP_PREFIX_ADDRESS,
+ 16, 1, rx, len, false);
+ err = -5963;
+ break;
+ }
+ }
+ return err;
+}
+
+struct hsspi_block *hsspi_test_get(struct hsspi_layer *layer, u16 length)
+{
+ struct hsspi_block *blk = kzalloc(sizeof(*blk) + length, GFP_KERNEL);
+ if (blk) {
+ blk->data = blk + 1;
+ blk->size = length;
+ blk->length = length;
+ }
+ return blk;
+}
+
+void hsspi_test_set_inter_frame_ms(int ms)
+{
+ sleep_inter_frame_ms = ms;
+}
+
+void hsspi_test_received(struct hsspi_layer *layer,
+ struct hsspi_block *blk, int status)
+{
+ static uint64_t bytes, msgs, errors, bytes0, msgs0, errors0;
+ static time64_t last_perf_dump;
+ int error = check_rx(blk->data, blk->length) ? 1 : 0;
+ time64_t now;
+ errors += error;
+
+ if (!last_perf_dump) {
+ last_perf_dump = ktime_get_seconds();
+ }
+ now = ktime_get_seconds();
+
+ /* inject latencies between each message and between the check
+ * of ss-ready and the xfer.
+ * The test is expected to fail if
+ * sleep_inter_frame_ms > CONFIG_PM_RET_SLEEP_DELAY_US
+ */
+ if (sleep_inter_frame_ms > 0) {
+ static int delay_us = 0;
+ test_sleep_after_ss_ready_us = sleep_inter_frame_ms * 1000 - delay_us;
+ usleep_range(delay_us, delay_us + 1);
+ delay_us += 100;
+ if (delay_us > sleep_inter_frame_ms * 1000)
+ delay_us = 0;
+ } else {
+ test_sleep_after_ss_ready_us = 0;
+ }
+ bytes += blk->length;
+ msgs++;
+ error |= hsspi_send(ghsspi, layer, blk);
+ if (error || ((msgs % 100) == 0))
+ pr_info("hsspi test: bytes received %llu, msgs %llu, errors %llu\n",
+ bytes, msgs, errors);
+ if (now > last_perf_dump) {
+ uint64_t dbytes = bytes >= bytes0 ? bytes - bytes0 : ~0ULL - bytes0 + bytes;
+ uint64_t dmsgs = msgs >= msgs0 ? msgs - msgs0 : ~0ULL - msgs0 + msgs;
+ uint64_t derrors = errors >= errors0 ? errors - errors0 : ~0ULL - errors0 + errors;
+ pr_info("hsspi test perfs: %llu B/s, %llu msgs/s, %llu errors/s\n",
+ dbytes / (now - last_perf_dump), dmsgs / (now - last_perf_dump),
+ derrors / (now - last_perf_dump));
+ bytes0 = bytes;
+ msgs0 = msgs;
+ errors0 = errors;
+ last_perf_dump = now;
+ }
+}
+
+void hsspi_test_sent(struct hsspi_layer *layer,
+ struct hsspi_block *blk, int status)
+{
+ static uint64_t bytes, msgs, errors;
+ errors += status ? 1 : 0;
+ msgs++;
+ bytes += blk->length;
+ if (status || ((msgs % 100) == 0))
+ pr_info("hsspi test: bytes sent %llu, msgs %llu, errors %llu\n",
+ bytes, msgs, errors);
+ kfree(blk);
+}