blob: ae02d52e04c52cc7b6dd829f34b3b100927e82a7 [file] [log] [blame]
// 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);
}