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

ipu_irq.c (8917B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2008
      4 * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
      5 */
      6
      7#include <linux/init.h>
      8#include <linux/err.h>
      9#include <linux/spinlock.h>
     10#include <linux/delay.h>
     11#include <linux/clk.h>
     12#include <linux/irq.h>
     13#include <linux/io.h>
     14#include <linux/module.h>
     15#include <linux/dma/ipu-dma.h>
     16
     17#include "ipu_intern.h"
     18
     19/*
     20 * Register read / write - shall be inlined by the compiler
     21 */
     22static u32 ipu_read_reg(struct ipu *ipu, unsigned long reg)
     23{
     24	return __raw_readl(ipu->reg_ipu + reg);
     25}
     26
     27static void ipu_write_reg(struct ipu *ipu, u32 value, unsigned long reg)
     28{
     29	__raw_writel(value, ipu->reg_ipu + reg);
     30}
     31
     32
     33/*
     34 * IPU IRQ chip driver
     35 */
     36
     37#define IPU_IRQ_NR_FN_BANKS 3
     38#define IPU_IRQ_NR_ERR_BANKS 2
     39#define IPU_IRQ_NR_BANKS (IPU_IRQ_NR_FN_BANKS + IPU_IRQ_NR_ERR_BANKS)
     40
     41struct ipu_irq_bank {
     42	unsigned int	control;
     43	unsigned int	status;
     44	struct ipu	*ipu;
     45};
     46
     47static struct ipu_irq_bank irq_bank[IPU_IRQ_NR_BANKS] = {
     48	/* 3 groups of functional interrupts */
     49	{
     50		.control	= IPU_INT_CTRL_1,
     51		.status		= IPU_INT_STAT_1,
     52	}, {
     53		.control	= IPU_INT_CTRL_2,
     54		.status		= IPU_INT_STAT_2,
     55	}, {
     56		.control	= IPU_INT_CTRL_3,
     57		.status		= IPU_INT_STAT_3,
     58	},
     59	/* 2 groups of error interrupts */
     60	{
     61		.control	= IPU_INT_CTRL_4,
     62		.status		= IPU_INT_STAT_4,
     63	}, {
     64		.control	= IPU_INT_CTRL_5,
     65		.status		= IPU_INT_STAT_5,
     66	},
     67};
     68
     69struct ipu_irq_map {
     70	unsigned int		irq;
     71	int			source;
     72	struct ipu_irq_bank	*bank;
     73	struct ipu		*ipu;
     74};
     75
     76static struct ipu_irq_map irq_map[CONFIG_MX3_IPU_IRQS];
     77/* Protects allocations from the above array of maps */
     78static DEFINE_MUTEX(map_lock);
     79/* Protects register accesses and individual mappings */
     80static DEFINE_RAW_SPINLOCK(bank_lock);
     81
     82static struct ipu_irq_map *src2map(unsigned int src)
     83{
     84	int i;
     85
     86	for (i = 0; i < CONFIG_MX3_IPU_IRQS; i++)
     87		if (irq_map[i].source == src)
     88			return irq_map + i;
     89
     90	return NULL;
     91}
     92
     93static void ipu_irq_unmask(struct irq_data *d)
     94{
     95	struct ipu_irq_map *map = irq_data_get_irq_chip_data(d);
     96	struct ipu_irq_bank *bank;
     97	uint32_t reg;
     98	unsigned long lock_flags;
     99
    100	raw_spin_lock_irqsave(&bank_lock, lock_flags);
    101
    102	bank = map->bank;
    103	if (!bank) {
    104		raw_spin_unlock_irqrestore(&bank_lock, lock_flags);
    105		pr_err("IPU: %s(%u) - unmapped!\n", __func__, d->irq);
    106		return;
    107	}
    108
    109	reg = ipu_read_reg(bank->ipu, bank->control);
    110	reg |= (1UL << (map->source & 31));
    111	ipu_write_reg(bank->ipu, reg, bank->control);
    112
    113	raw_spin_unlock_irqrestore(&bank_lock, lock_flags);
    114}
    115
    116static void ipu_irq_mask(struct irq_data *d)
    117{
    118	struct ipu_irq_map *map = irq_data_get_irq_chip_data(d);
    119	struct ipu_irq_bank *bank;
    120	uint32_t reg;
    121	unsigned long lock_flags;
    122
    123	raw_spin_lock_irqsave(&bank_lock, lock_flags);
    124
    125	bank = map->bank;
    126	if (!bank) {
    127		raw_spin_unlock_irqrestore(&bank_lock, lock_flags);
    128		pr_err("IPU: %s(%u) - unmapped!\n", __func__, d->irq);
    129		return;
    130	}
    131
    132	reg = ipu_read_reg(bank->ipu, bank->control);
    133	reg &= ~(1UL << (map->source & 31));
    134	ipu_write_reg(bank->ipu, reg, bank->control);
    135
    136	raw_spin_unlock_irqrestore(&bank_lock, lock_flags);
    137}
    138
    139static void ipu_irq_ack(struct irq_data *d)
    140{
    141	struct ipu_irq_map *map = irq_data_get_irq_chip_data(d);
    142	struct ipu_irq_bank *bank;
    143	unsigned long lock_flags;
    144
    145	raw_spin_lock_irqsave(&bank_lock, lock_flags);
    146
    147	bank = map->bank;
    148	if (!bank) {
    149		raw_spin_unlock_irqrestore(&bank_lock, lock_flags);
    150		pr_err("IPU: %s(%u) - unmapped!\n", __func__, d->irq);
    151		return;
    152	}
    153
    154	ipu_write_reg(bank->ipu, 1UL << (map->source & 31), bank->status);
    155	raw_spin_unlock_irqrestore(&bank_lock, lock_flags);
    156}
    157
    158/**
    159 * ipu_irq_status() - returns the current interrupt status of the specified IRQ.
    160 * @irq:	interrupt line to get status for.
    161 * @return:	true if the interrupt is pending/asserted or false if the
    162 *		interrupt is not pending.
    163 */
    164bool ipu_irq_status(unsigned int irq)
    165{
    166	struct ipu_irq_map *map = irq_get_chip_data(irq);
    167	struct ipu_irq_bank *bank;
    168	unsigned long lock_flags;
    169	bool ret;
    170
    171	raw_spin_lock_irqsave(&bank_lock, lock_flags);
    172	bank = map->bank;
    173	ret = bank && ipu_read_reg(bank->ipu, bank->status) &
    174		(1UL << (map->source & 31));
    175	raw_spin_unlock_irqrestore(&bank_lock, lock_flags);
    176
    177	return ret;
    178}
    179
    180/**
    181 * ipu_irq_map() - map an IPU interrupt source to an IRQ number
    182 * @source:	interrupt source bit position (see below)
    183 * @return:	mapped IRQ number or negative error code
    184 *
    185 * The source parameter has to be explained further. On i.MX31 IPU has 137 IRQ
    186 * sources, they are broken down in 5 32-bit registers, like 32, 32, 24, 32, 17.
    187 * However, the source argument of this function is not the sequence number of
    188 * the possible IRQ, but rather its bit position. So, first interrupt in fourth
    189 * register has source number 96, and not 88. This makes calculations easier,
    190 * and also provides forward compatibility with any future IPU implementations
    191 * with any interrupt bit assignments.
    192 */
    193int ipu_irq_map(unsigned int source)
    194{
    195	int i, ret = -ENOMEM;
    196	struct ipu_irq_map *map;
    197
    198	might_sleep();
    199
    200	mutex_lock(&map_lock);
    201	map = src2map(source);
    202	if (map) {
    203		pr_err("IPU: Source %u already mapped to IRQ %u\n", source, map->irq);
    204		ret = -EBUSY;
    205		goto out;
    206	}
    207
    208	for (i = 0; i < CONFIG_MX3_IPU_IRQS; i++) {
    209		if (irq_map[i].source < 0) {
    210			unsigned long lock_flags;
    211
    212			raw_spin_lock_irqsave(&bank_lock, lock_flags);
    213			irq_map[i].source = source;
    214			irq_map[i].bank = irq_bank + source / 32;
    215			raw_spin_unlock_irqrestore(&bank_lock, lock_flags);
    216
    217			ret = irq_map[i].irq;
    218			pr_debug("IPU: mapped source %u to IRQ %u\n",
    219				 source, ret);
    220			break;
    221		}
    222	}
    223out:
    224	mutex_unlock(&map_lock);
    225
    226	if (ret < 0)
    227		pr_err("IPU: couldn't map source %u: %d\n", source, ret);
    228
    229	return ret;
    230}
    231
    232/**
    233 * ipu_irq_unmap() - unmap an IPU interrupt source
    234 * @source:	interrupt source bit position (see ipu_irq_map())
    235 * @return:	0 or negative error code
    236 */
    237int ipu_irq_unmap(unsigned int source)
    238{
    239	int i, ret = -EINVAL;
    240
    241	might_sleep();
    242
    243	mutex_lock(&map_lock);
    244	for (i = 0; i < CONFIG_MX3_IPU_IRQS; i++) {
    245		if (irq_map[i].source == source) {
    246			unsigned long lock_flags;
    247
    248			pr_debug("IPU: unmapped source %u from IRQ %u\n",
    249				 source, irq_map[i].irq);
    250
    251			raw_spin_lock_irqsave(&bank_lock, lock_flags);
    252			irq_map[i].source = -EINVAL;
    253			irq_map[i].bank = NULL;
    254			raw_spin_unlock_irqrestore(&bank_lock, lock_flags);
    255
    256			ret = 0;
    257			break;
    258		}
    259	}
    260	mutex_unlock(&map_lock);
    261
    262	return ret;
    263}
    264
    265/* Chained IRQ handler for IPU function and error interrupt */
    266static void ipu_irq_handler(struct irq_desc *desc)
    267{
    268	struct ipu *ipu = irq_desc_get_handler_data(desc);
    269	u32 status;
    270	int i, line;
    271
    272	for (i = 0; i < IPU_IRQ_NR_BANKS; i++) {
    273		struct ipu_irq_bank *bank = irq_bank + i;
    274
    275		raw_spin_lock(&bank_lock);
    276		status = ipu_read_reg(ipu, bank->status);
    277		/*
    278		 * Don't think we have to clear all interrupts here, they will
    279		 * be acked by ->handle_irq() (handle_level_irq). However, we
    280		 * might want to clear unhandled interrupts after the loop...
    281		 */
    282		status &= ipu_read_reg(ipu, bank->control);
    283		raw_spin_unlock(&bank_lock);
    284		while ((line = ffs(status))) {
    285			struct ipu_irq_map *map;
    286			unsigned int irq;
    287
    288			line--;
    289			status &= ~(1UL << line);
    290
    291			raw_spin_lock(&bank_lock);
    292			map = src2map(32 * i + line);
    293			if (!map) {
    294				raw_spin_unlock(&bank_lock);
    295				pr_err("IPU: Interrupt on unmapped source %u bank %d\n",
    296				       line, i);
    297				continue;
    298			}
    299			irq = map->irq;
    300			raw_spin_unlock(&bank_lock);
    301			generic_handle_irq(irq);
    302		}
    303	}
    304}
    305
    306static struct irq_chip ipu_irq_chip = {
    307	.name		= "ipu_irq",
    308	.irq_ack	= ipu_irq_ack,
    309	.irq_mask	= ipu_irq_mask,
    310	.irq_unmask	= ipu_irq_unmask,
    311};
    312
    313/* Install the IRQ handler */
    314int __init ipu_irq_attach_irq(struct ipu *ipu, struct platform_device *dev)
    315{
    316	unsigned int irq, i;
    317	int irq_base = irq_alloc_descs(-1, 0, CONFIG_MX3_IPU_IRQS,
    318				       numa_node_id());
    319
    320	if (irq_base < 0)
    321		return irq_base;
    322
    323	for (i = 0; i < IPU_IRQ_NR_BANKS; i++)
    324		irq_bank[i].ipu = ipu;
    325
    326	for (i = 0; i < CONFIG_MX3_IPU_IRQS; i++) {
    327		int ret;
    328
    329		irq = irq_base + i;
    330		ret = irq_set_chip(irq, &ipu_irq_chip);
    331		if (ret < 0)
    332			return ret;
    333		ret = irq_set_chip_data(irq, irq_map + i);
    334		if (ret < 0)
    335			return ret;
    336		irq_map[i].ipu = ipu;
    337		irq_map[i].irq = irq;
    338		irq_map[i].source = -EINVAL;
    339		irq_set_handler(irq, handle_level_irq);
    340		irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
    341	}
    342
    343	irq_set_chained_handler_and_data(ipu->irq_fn, ipu_irq_handler, ipu);
    344
    345	irq_set_chained_handler_and_data(ipu->irq_err, ipu_irq_handler, ipu);
    346
    347	ipu->irq_base = irq_base;
    348
    349	return 0;
    350}
    351
    352void ipu_irq_detach_irq(struct ipu *ipu, struct platform_device *dev)
    353{
    354	unsigned int irq, irq_base;
    355
    356	irq_base = ipu->irq_base;
    357
    358	irq_set_chained_handler_and_data(ipu->irq_fn, NULL, NULL);
    359
    360	irq_set_chained_handler_and_data(ipu->irq_err, NULL, NULL);
    361
    362	for (irq = irq_base; irq < irq_base + CONFIG_MX3_IPU_IRQS; irq++) {
    363		irq_set_status_flags(irq, IRQ_NOREQUEST);
    364		irq_set_chip(irq, NULL);
    365		irq_set_chip_data(irq, NULL);
    366	}
    367}