drivers/gpu/host1x/hw/intr_hw.c

Source file repositories/reference/linux-study-clean/drivers/gpu/host1x/hw/intr_hw.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/host1x/hw/intr_hw.c
Extension
.c
Size
4500 bytes
Lines
155
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Tegra host1x Interrupt Management
 *
 * Copyright (C) 2010 Google, Inc.
 * Copyright (c) 2010-2013, NVIDIA Corporation.
 */

#include <linux/io.h>

#include "../intr.h"
#include "../dev.h"

static void process_32_syncpts(struct host1x *host, unsigned long val, u32 reg_offset)
{
	unsigned int id;

	if (!val)
		return;

	host1x_sync_writel(host, val, HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(reg_offset));
	host1x_sync_writel(host, val, HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(reg_offset));

	for_each_set_bit(id, &val, 32)
		host1x_intr_handle_interrupt(host, reg_offset * 32 + id);
}

static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id)
{
	struct host1x_intr_irq_data *irq_data = dev_id;
	struct host1x *host = irq_data->host;
	unsigned long reg;
	unsigned int i;

#if !defined(CONFIG_64BIT)
	for (i = irq_data->offset; i < DIV_ROUND_UP(host->info->nb_pts, 32);
	     i += host->num_syncpt_irqs) {
		reg = host1x_sync_readl(host,
			HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));

		process_32_syncpts(host, reg, i);
	}
#elif HOST1X_HW == 6 || HOST1X_HW == 7
	/*
	 * Tegra186 and Tegra194 have the first INT_STATUS register not 64-bit aligned,
	 * and only have one interrupt line.
	 */
	reg = host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(0));
	process_32_syncpts(host, reg, 0);

	for (i = 1; i < (host->info->nb_pts / 32) - 1; i += 2) {
		reg = host1x_sync_readq(host,
			HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));

		process_32_syncpts(host, lower_32_bits(reg), i);
		process_32_syncpts(host, upper_32_bits(reg), i + 1);
	}

	reg = host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));
	process_32_syncpts(host, reg, i);
#else
	/* All 64-bit capable SoCs have number of syncpoints divisible by 64 */
	for (i = irq_data->offset; i < DIV_ROUND_UP(host->info->nb_pts, 64);
	     i += host->num_syncpt_irqs) {
		reg = host1x_sync_readq(host,
			HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i * 2));

		process_32_syncpts(host, lower_32_bits(reg), i * 2 + 0);
		process_32_syncpts(host, upper_32_bits(reg), i * 2 + 1);
	}
#endif

	return IRQ_HANDLED;
}

static void host1x_intr_disable_all_syncpt_intrs(struct host1x *host)
{
	unsigned int i;

	for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); ++i) {
		host1x_sync_writel(host, 0xffffffffu,
			HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(i));
		host1x_sync_writel(host, 0xffffffffu,
			HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));
	}
}

static int
host1x_intr_init_host_sync(struct host1x *host, u32 cpm)
{

Annotation

Implementation Notes