forked from Minki/linux
3b20eb2372
Based on 1 normalized pattern(s): this program is free software you can redistribute it and or modify it under the terms and conditions of the gnu general public license version 2 as published by the free software foundation this program is distributed in the hope it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details you should have received a copy of the gnu general public license along with this program if not write to the free software foundation inc 59 temple place suite 330 boston ma 02111 1307 usa extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference in 33 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Allison Randal <allison@lohutok.net> Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org> Reviewed-by: Alexios Zavras <alexios.zavras@intel.com> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190530000435.254582722@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
153 lines
2.9 KiB
C
153 lines
2.9 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* arch/arm/mach-iop13xx/msi.c
|
|
*
|
|
* PCI MSI support for the iop13xx processor
|
|
*
|
|
* Copyright (c) 2006, Intel Corporation.
|
|
*/
|
|
#include <linux/pci.h>
|
|
#include <linux/msi.h>
|
|
#include <asm/mach/irq.h>
|
|
#include <asm/irq.h>
|
|
#include <mach/irqs.h>
|
|
|
|
/* IMIPR0 CP6 R8 Page 1
|
|
*/
|
|
static u32 read_imipr_0(void)
|
|
{
|
|
u32 val;
|
|
asm volatile("mrc p6, 0, %0, c8, c1, 0":"=r" (val));
|
|
return val;
|
|
}
|
|
static void write_imipr_0(u32 val)
|
|
{
|
|
asm volatile("mcr p6, 0, %0, c8, c1, 0"::"r" (val));
|
|
}
|
|
|
|
/* IMIPR1 CP6 R9 Page 1
|
|
*/
|
|
static u32 read_imipr_1(void)
|
|
{
|
|
u32 val;
|
|
asm volatile("mrc p6, 0, %0, c9, c1, 0":"=r" (val));
|
|
return val;
|
|
}
|
|
static void write_imipr_1(u32 val)
|
|
{
|
|
asm volatile("mcr p6, 0, %0, c9, c1, 0"::"r" (val));
|
|
}
|
|
|
|
/* IMIPR2 CP6 R10 Page 1
|
|
*/
|
|
static u32 read_imipr_2(void)
|
|
{
|
|
u32 val;
|
|
asm volatile("mrc p6, 0, %0, c10, c1, 0":"=r" (val));
|
|
return val;
|
|
}
|
|
static void write_imipr_2(u32 val)
|
|
{
|
|
asm volatile("mcr p6, 0, %0, c10, c1, 0"::"r" (val));
|
|
}
|
|
|
|
/* IMIPR3 CP6 R11 Page 1
|
|
*/
|
|
static u32 read_imipr_3(void)
|
|
{
|
|
u32 val;
|
|
asm volatile("mrc p6, 0, %0, c11, c1, 0":"=r" (val));
|
|
return val;
|
|
}
|
|
static void write_imipr_3(u32 val)
|
|
{
|
|
asm volatile("mcr p6, 0, %0, c11, c1, 0"::"r" (val));
|
|
}
|
|
|
|
static u32 (*read_imipr[])(void) = {
|
|
read_imipr_0,
|
|
read_imipr_1,
|
|
read_imipr_2,
|
|
read_imipr_3,
|
|
};
|
|
|
|
static void (*write_imipr[])(u32) = {
|
|
write_imipr_0,
|
|
write_imipr_1,
|
|
write_imipr_2,
|
|
write_imipr_3,
|
|
};
|
|
|
|
static void iop13xx_msi_handler(struct irq_desc *desc)
|
|
{
|
|
int i, j;
|
|
unsigned long status;
|
|
|
|
/* read IMIPR registers and find any active interrupts,
|
|
* then call ISR for each active interrupt
|
|
*/
|
|
for (i = 0; i < ARRAY_SIZE(read_imipr); i++) {
|
|
status = (read_imipr[i])();
|
|
if (!status)
|
|
continue;
|
|
|
|
do {
|
|
j = find_first_bit(&status, 32);
|
|
(write_imipr[i])(1 << j); /* write back to clear bit */
|
|
generic_handle_irq(IRQ_IOP13XX_MSI_0 + j + (32*i));
|
|
status = (read_imipr[i])();
|
|
} while (status);
|
|
}
|
|
}
|
|
|
|
void __init iop13xx_msi_init(void)
|
|
{
|
|
irq_set_chained_handler(IRQ_IOP13XX_INBD_MSI, iop13xx_msi_handler);
|
|
}
|
|
|
|
static void iop13xx_msi_nop(struct irq_data *d)
|
|
{
|
|
return;
|
|
}
|
|
|
|
static struct irq_chip iop13xx_msi_chip = {
|
|
.name = "PCI-MSI",
|
|
.irq_ack = iop13xx_msi_nop,
|
|
.irq_enable = pci_msi_unmask_irq,
|
|
.irq_disable = pci_msi_mask_irq,
|
|
.irq_mask = pci_msi_mask_irq,
|
|
.irq_unmask = pci_msi_unmask_irq,
|
|
};
|
|
|
|
int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
|
|
{
|
|
int id, irq = irq_alloc_desc_from(IRQ_IOP13XX_MSI_0, -1);
|
|
struct msi_msg msg;
|
|
|
|
if (irq < 0)
|
|
return irq;
|
|
|
|
if (irq >= NR_IOP13XX_IRQS) {
|
|
irq_free_desc(irq);
|
|
return -ENOSPC;
|
|
}
|
|
|
|
irq_set_msi_desc(irq, desc);
|
|
|
|
msg.address_hi = 0x0;
|
|
msg.address_lo = IOP13XX_MU_MIMR_PCI;
|
|
|
|
id = iop13xx_cpu_id();
|
|
msg.data = (id << IOP13XX_MU_MIMR_CORE_SELECT) | (irq & 0x7f);
|
|
|
|
pci_write_msi_msg(irq, &msg);
|
|
irq_set_chip_and_handler(irq, &iop13xx_msi_chip, handle_simple_irq);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void arch_teardown_msi_irq(unsigned int irq)
|
|
{
|
|
irq_free_desc(irq);
|
|
}
|