cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

intr_hw.c (3857B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Tegra host1x Interrupt Management
      4 *
      5 * Copyright (C) 2010 Google, Inc.
      6 * Copyright (c) 2010-2013, NVIDIA Corporation.
      7 */
      8
      9#include <linux/interrupt.h>
     10#include <linux/irq.h>
     11#include <linux/io.h>
     12
     13#include "../intr.h"
     14#include "../dev.h"
     15
     16/*
     17 * Sync point threshold interrupt service function
     18 * Handles sync point threshold triggers, in interrupt context
     19 */
     20static void host1x_intr_syncpt_handle(struct host1x_syncpt *syncpt)
     21{
     22	unsigned int id = syncpt->id;
     23	struct host1x *host = syncpt->host;
     24
     25	host1x_sync_writel(host, BIT(id % 32),
     26		HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(id / 32));
     27	host1x_sync_writel(host, BIT(id % 32),
     28		HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(id / 32));
     29
     30	schedule_work(&syncpt->intr.work);
     31}
     32
     33static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id)
     34{
     35	struct host1x *host = dev_id;
     36	unsigned long reg;
     37	unsigned int i, id;
     38
     39	for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); i++) {
     40		reg = host1x_sync_readl(host,
     41			HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));
     42		for_each_set_bit(id, &reg, 32) {
     43			struct host1x_syncpt *syncpt =
     44				host->syncpt + (i * 32 + id);
     45			host1x_intr_syncpt_handle(syncpt);
     46		}
     47	}
     48
     49	return IRQ_HANDLED;
     50}
     51
     52static void _host1x_intr_disable_all_syncpt_intrs(struct host1x *host)
     53{
     54	unsigned int i;
     55
     56	for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); ++i) {
     57		host1x_sync_writel(host, 0xffffffffu,
     58			HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(i));
     59		host1x_sync_writel(host, 0xffffffffu,
     60			HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));
     61	}
     62}
     63
     64static void intr_hw_init(struct host1x *host, u32 cpm)
     65{
     66#if HOST1X_HW < 6
     67	/* disable the ip_busy_timeout. this prevents write drops */
     68	host1x_sync_writel(host, 0, HOST1X_SYNC_IP_BUSY_TIMEOUT);
     69
     70	/*
     71	 * increase the auto-ack timout to the maximum value. 2d will hang
     72	 * otherwise on Tegra2.
     73	 */
     74	host1x_sync_writel(host, 0xff, HOST1X_SYNC_CTXSW_TIMEOUT_CFG);
     75
     76	/* update host clocks per usec */
     77	host1x_sync_writel(host, cpm, HOST1X_SYNC_USEC_CLK);
     78#endif
     79}
     80
     81static int
     82_host1x_intr_init_host_sync(struct host1x *host, u32 cpm,
     83			    void (*syncpt_thresh_work)(struct work_struct *))
     84{
     85	unsigned int i;
     86	int err;
     87
     88	host1x_hw_intr_disable_all_syncpt_intrs(host);
     89
     90	for (i = 0; i < host->info->nb_pts; i++)
     91		INIT_WORK(&host->syncpt[i].intr.work, syncpt_thresh_work);
     92
     93	err = devm_request_irq(host->dev, host->intr_syncpt_irq,
     94			       syncpt_thresh_isr, IRQF_SHARED,
     95			       "host1x_syncpt", host);
     96	if (err < 0) {
     97		WARN_ON(1);
     98		return err;
     99	}
    100
    101	intr_hw_init(host, cpm);
    102
    103	return 0;
    104}
    105
    106static void _host1x_intr_set_syncpt_threshold(struct host1x *host,
    107					      unsigned int id,
    108					      u32 thresh)
    109{
    110	host1x_sync_writel(host, thresh, HOST1X_SYNC_SYNCPT_INT_THRESH(id));
    111}
    112
    113static void _host1x_intr_enable_syncpt_intr(struct host1x *host,
    114					    unsigned int id)
    115{
    116	host1x_sync_writel(host, BIT(id % 32),
    117		HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(id / 32));
    118}
    119
    120static void _host1x_intr_disable_syncpt_intr(struct host1x *host,
    121					     unsigned int id)
    122{
    123	host1x_sync_writel(host, BIT(id % 32),
    124		HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(id / 32));
    125	host1x_sync_writel(host, BIT(id % 32),
    126		HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(id / 32));
    127}
    128
    129static int _host1x_free_syncpt_irq(struct host1x *host)
    130{
    131	unsigned int i;
    132
    133	devm_free_irq(host->dev, host->intr_syncpt_irq, host);
    134
    135	for (i = 0; i < host->info->nb_pts; i++)
    136		cancel_work_sync(&host->syncpt[i].intr.work);
    137
    138	return 0;
    139}
    140
    141static const struct host1x_intr_ops host1x_intr_ops = {
    142	.init_host_sync = _host1x_intr_init_host_sync,
    143	.set_syncpt_threshold = _host1x_intr_set_syncpt_threshold,
    144	.enable_syncpt_intr = _host1x_intr_enable_syncpt_intr,
    145	.disable_syncpt_intr = _host1x_intr_disable_syncpt_intr,
    146	.disable_all_syncpt_intrs = _host1x_intr_disable_all_syncpt_intrs,
    147	.free_syncpt_irq = _host1x_free_syncpt_irq,
    148};