Linux Audio

Check our new training course

Embedded Linux Audio

Check our new training course
with Creative Commons CC-BY-SA
lecture materials

Bootlin logo

Elixir Cross Referencer

Loading...
/*
 * Copyright (c) 2021 BayLibre, SAS
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/ztest.h>
#include <zephyr/device.h>
#include <zephyr/drivers/interrupt_controller/gicv3_its.h>

#define DT_DRV_COMPAT   arm_gic_v3_its

static volatile unsigned int last_lpi_irq_num;

static void lpi_irq_handle(const void *parameter)
{
	uintptr_t i = (uintptr_t)parameter;

	last_lpi_irq_num = i;
}

/* Generate a DeviceID over the whole 16bits */
#define ITS_TEST_DEV(id)        ((((id + 256) % 16) << 12) | (((id + 256) % 24) << 8) | (id & 0xff))

/* Cover up to 8192 LPIs over 256 DevicesIDs and 32 EventIDs per DeviceID */
#define ITS_TEST_NUM_DEVS       256
#define ITS_TEST_NUM_ITES       32

/* Do not test all 8192 irqs, iterate with a prime offset to cover most of the possible event_ids */
#define ITS_TEST_NEXT		13

/* Active-wait loops waiting for an interrupt */
#define ITS_TEST_LOOPS		10

unsigned int vectors[ITS_TEST_NUM_DEVS][ITS_TEST_NUM_ITES];

ZTEST(arm64_gicv3_its, test_gicv3_its_alloc)
{
	int devn, event_id;
	const struct device *const dev = DEVICE_DT_INST_GET(0);

	zassert_false(dev == NULL, "");

	for (devn = 0; devn < ITS_TEST_NUM_DEVS; ++devn) {
		int device_id = ITS_TEST_DEV(devn);

		zassert_true(its_setup_deviceid(dev, device_id, ITS_TEST_NUM_ITES) == 0, "");

		for (event_id = 0; event_id < ITS_TEST_NUM_ITES; ++event_id) {
			vectors[devn][event_id] = its_alloc_intid(dev);
			zassert_true(vectors[devn][event_id] >= 8192, "");
			zassert_true(vectors[devn][event_id] < CONFIG_NUM_IRQS, "");

			zassert_true(its_map_intid(dev, device_id, event_id,
						   vectors[devn][event_id]) == 0, "");
		}
	}
}

ZTEST(arm64_gicv3_its, test_gicv3_its_connect)
{
	int devn, event_id;
	const struct device *const dev = DEVICE_DT_INST_GET(0);
	unsigned int remain = 0;

	zassert_false(dev == NULL, "");

	for (devn = 0; devn < ITS_TEST_NUM_DEVS; ++devn) {
		for (event_id = remain; event_id < ITS_TEST_NUM_ITES; event_id += ITS_TEST_NEXT) {
			unsigned int irqn = vectors[devn][event_id];

			zassert_true(irq_connect_dynamic(irqn, 0, lpi_irq_handle,
							 (void *)(uintptr_t)(irqn), 0) == irqn, "");

			irq_enable(irqn);
		}
		remain = event_id - ITS_TEST_NUM_ITES;
	}
}

ZTEST(arm64_gicv3_its, test_gicv3_its_irq_simple)
{
	const struct device *const dev = DEVICE_DT_INST_GET(0);
	unsigned int irqn = vectors[0][0];
	unsigned int timeout;
	int device_id = ITS_TEST_DEV(0);
	int event_id = 0;

	zassert_false(dev == NULL, "");

	last_lpi_irq_num = 0;
	zassert_true(its_send_int(dev, device_id, event_id) == 0, "");

	timeout = ITS_TEST_LOOPS;
	while (!last_lpi_irq_num && timeout) {
		timeout--;
	}

	zassert_true(last_lpi_irq_num == irqn,
			"IRQ %d of DeviceID %x EventID %d failed",
			irqn, device_id, event_id);
}

ZTEST(arm64_gicv3_its, test_gicv3_its_irq_disable)
{
	const struct device *const dev = DEVICE_DT_INST_GET(0);
	unsigned int irqn = vectors[0][0];
	unsigned int timeout;
	int device_id = ITS_TEST_DEV(0);
	int event_id = 0;

	zassert_false(dev == NULL, "");

	irq_disable(irqn);

	last_lpi_irq_num = 0;
	zassert_true(its_send_int(dev, device_id, event_id) == 0, "");

	timeout = ITS_TEST_LOOPS;
	while (!last_lpi_irq_num && timeout) {
		timeout--;
	}

	zassert_true(last_lpi_irq_num == 0,
			"IRQ %d of DeviceID %x EventID %d disable failed",
			irqn, device_id, event_id);

	irq_enable(irqn);

	last_lpi_irq_num = 0;
	zassert_true(its_send_int(dev, device_id, event_id) == 0, "");

	timeout = ITS_TEST_LOOPS;
	while (!last_lpi_irq_num && timeout) {
		timeout--;
	}

	zassert_true(last_lpi_irq_num == irqn,
			"IRQ %d of DeviceID %x EventID %d re-enable failed",
			irqn, device_id, event_id);
}

ZTEST(arm64_gicv3_its, test_gicv3_its_irq)
{
	int devn, event_id;
	const struct device *const dev = DEVICE_DT_INST_GET(0);
	unsigned int timeout;
	unsigned int remain = 0;

	zassert_false(dev == NULL, "");

	for (devn = 0; devn < ITS_TEST_NUM_DEVS; ++devn) {
		int device_id = ITS_TEST_DEV(devn);

		for (event_id = remain; event_id < ITS_TEST_NUM_ITES; event_id += ITS_TEST_NEXT) {
			unsigned int irqn = vectors[devn][event_id];

			last_lpi_irq_num = 0;
			zassert_true(its_send_int(dev, device_id, event_id) == 0, "");

			timeout = ITS_TEST_LOOPS;
			while (!last_lpi_irq_num && timeout) {
				timeout--;
			}

			zassert_true(last_lpi_irq_num == irqn,
				     "IRQ %d of DeviceID %x EventID %d failed",
				     irqn, device_id, event_id);
		}

		remain = event_id - ITS_TEST_NUM_ITES;
	}
}

ZTEST_SUITE(arm64_gicv3_its, NULL, NULL, NULL, NULL, NULL);