Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq updates from Thomas Gleixner:
 "This updated pull request does not contain the last few GIC related
  patches which were reported to cause a regression.  There is a fix
  available, but I let it breed for a couple of days first.

  The irq departement provides:

   - new infrastructure to support non PCI based MSI interrupts
   - a couple of new irq chip drivers
   - the usual pile of fixlets and updates to irq chip drivers
   - preparatory changes for removal of the irq argument from interrupt
     flow handlers
   - preparatory changes to remove IRQF_VALID"

* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (129 commits)
  irqchip/imx-gpcv2: IMX GPCv2 driver for wakeup sources
  irqchip: Add bcm2836 interrupt controller for Raspberry Pi 2
  irqchip: Add documentation for the bcm2836 interrupt controller
  irqchip/bcm2835: Add support for being used as a second level controller
  irqchip/bcm2835: Refactor handle_IRQ() calls out of MAKE_HWIRQ
  PCI: xilinx: Fix typo in function name
  irqchip/gic: Ensure gic_cpu_if_up/down() programs correct GIC instance
  irqchip/gic: Only allow the primary GIC to set the CPU map
  PCI/MSI: pci-xgene-msi: Consolidate chained IRQ handler install/remove
  unicore32/irq: Prepare puv3_gpio_handler for irq argument removal
  tile/pci_gx: Prepare trio_handle_level_irq for irq argument removal
  m68k/irq: Prepare irq handlers for irq argument removal
  C6X/megamode-pic: Prepare megamod_irq_cascade for irq argument removal
  blackfin: Prepare irq handlers for irq argument removal
  arc/irq: Prepare idu_cascade_isr for irq argument removal
  sparc/irq: Use access helper irq_data_get_affinity_mask()
  sparc/irq: Use helper irq_data_get_irq_handler_data()
  parisc/irq: Use access helper irq_data_get_affinity_mask()
  mn10300/irq: Use access helper irq_data_get_affinity_mask()
  irqchip/i8259: Prepare i8259_irq_dispatch for irq argument removal
  ...
This commit is contained in:
Linus Torvalds 2015-09-01 14:33:35 -07:00
commit 17e6b00ac4
161 changed files with 2208 additions and 849 deletions

View File

@ -5,9 +5,14 @@ The BCM2835 contains a custom top-level interrupt controller, which supports
controller, or the HW block containing it, is referred to occasionally
as "armctrl" in the SoC documentation, hence naming of this binding.
The BCM2836 contains the same interrupt controller with the same
interrupts, but the per-CPU interrupt controller is the root, and an
interrupt there indicates that the ARMCTRL has an interrupt to handle.
Required properties:
- compatible : should be "brcm,bcm2835-armctrl-ic"
- compatible : should be "brcm,bcm2835-armctrl-ic" or
"brcm,bcm2836-armctrl-ic"
- reg : Specifies base physical address and size of the registers.
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode an
@ -20,6 +25,12 @@ Required properties:
The 2nd cell contains the interrupt number within the bank. Valid values
are 0..7 for bank 0, and 0..31 for bank 1.
Additional required properties for brcm,bcm2836-armctrl-ic:
- interrupt-parent : Specifies the parent interrupt controller when this
controller is the second level.
- interrupts : Specifies the interrupt on the parent for this interrupt
controller to handle.
The interrupt sources are as follows:
Bank 0:
@ -102,9 +113,21 @@ Bank 2:
Example:
/* BCM2835, first level */
intc: interrupt-controller {
compatible = "brcm,bcm2835-armctrl-ic";
reg = <0x7e00b200 0x200>;
interrupt-controller;
#interrupt-cells = <2>;
};
/* BCM2836, second level */
intc: interrupt-controller {
compatible = "brcm,bcm2836-armctrl-ic";
reg = <0x7e00b200 0x200>;
interrupt-controller;
#interrupt-cells = <2>;
interrupt-parent = <&local_intc>;
interrupts = <8>;
};

View File

@ -0,0 +1,37 @@
BCM2836 per-CPU interrupt controller
The BCM2836 has a per-cpu interrupt controller for the timer, PMU
events, and SMP IPIs. One of the CPUs may receive interrupts for the
peripheral (GPU) events, which chain to the BCM2835-style interrupt
controller.
Required properties:
- compatible: Should be "brcm,bcm2836-l1-intc"
- reg: Specifies base physical address and size of the
registers
- interrupt-controller: Identifies the node as an interrupt controller
- #interrupt-cells: Specifies the number of cells needed to encode an
interrupt source. The value shall be 1
Please refer to interrupts.txt in this directory for details of the common
Interrupt Controllers bindings used by client devices.
The interrupt sources are as follows:
0: CNTPSIRQ
1: CNTPNSIRQ
2: CNTHPIRQ
3: CNTVIRQ
8: GPU_FAST
9: PMU_FAST
Example:
local_intc: local_intc {
compatible = "brcm,bcm2836-l1-intc";
reg = <0x40000000 0x100>;
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&local_intc>;
};

View File

@ -59,7 +59,7 @@ int irq_select_affinity(unsigned int irq)
cpu = (cpu < (NR_CPUS-1) ? cpu + 1 : 0);
last_cpu = cpu;
cpumask_copy(data->affinity, cpumask_of(cpu));
cpumask_copy(irq_data_get_affinity_mask(data), cpumask_of(cpu));
chip->irq_set_affinity(data, cpumask_of(cpu), false);
return 0;
}

View File

@ -252,9 +252,10 @@ static struct irq_chip idu_irq_chip = {
static int idu_first_irq;
static void idu_cascade_isr(unsigned int core_irq, struct irq_desc *desc)
static void idu_cascade_isr(unsigned int __core_irq, struct irq_desc *desc)
{
struct irq_domain *domain = irq_desc_get_handler_data(desc);
unsigned int core_irq = irq_desc_get_irq(desc);
unsigned int idu_irq;
idu_irq = core_irq - idu_first_irq;

View File

@ -62,8 +62,6 @@ static void __init r8a7779_map_io(void)
static void __init r8a7779_init_irq_dt(void)
{
gic_set_irqchip_flags(IRQCHIP_SKIP_SET_WAKE);
irqchip_init();
/* route all interrupts to ARM */

View File

@ -56,7 +56,6 @@ void __init ux500_init_irq(void)
struct device_node *np;
struct resource r;
gic_set_irqchip_flags(IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND);
irqchip_init();
np = of_find_compatible_node(NULL, NULL, "stericsson,db8500-prcmu");
of_address_to_resource(np, 0, &r);

View File

@ -80,7 +80,7 @@ static void tc2_pm_cpu_powerdown_prepare(unsigned int cpu, unsigned int cluster)
* to the CPU by disabling the GIC CPU IF to prevent wfi
* from completing execution behind power controller back
*/
gic_cpu_if_down();
gic_cpu_if_down(0);
}
static void tc2_pm_cluster_powerdown_prepare(unsigned int cluster)

View File

@ -186,7 +186,6 @@ static void __init zynq_map_io(void)
static void __init zynq_irq_init(void)
{
gic_set_irqchip_flags(IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND);
irqchip_init();
}

View File

@ -128,9 +128,9 @@ static int eic_set_irq_type(struct irq_data *d, unsigned int flow_type)
irqd_set_trigger_type(d, flow_type);
if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
__irq_set_handler_locked(irq, handle_level_irq);
irq_set_handler_locked(d, handle_level_irq);
else
__irq_set_handler_locked(irq, handle_edge_irq);
irq_set_handler_locked(d, handle_edge_irq);
return IRQ_SET_MASK_OK_NOCOPY;
}

View File

@ -286,7 +286,7 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
struct pio_device *pio = irq_desc_get_chip_data(desc);
unsigned gpio_irq;
gpio_irq = (unsigned) irq_get_handler_data(irq);
gpio_irq = (unsigned) irq_desc_get_handler_data(desc);
for (;;) {
u32 isr;
@ -312,7 +312,6 @@ gpio_irq_setup(struct pio_device *pio, int irq, int gpio_irq)
unsigned i;
irq_set_chip_data(irq, pio);
irq_set_handler_data(irq, (void *)gpio_irq);
for (i = 0; i < 32; i++, gpio_irq++) {
irq_set_chip_data(gpio_irq, pio);
@ -320,7 +319,8 @@ gpio_irq_setup(struct pio_device *pio, int irq, int gpio_irq)
handle_simple_irq);
}
irq_set_chained_handler(irq, gpio_irq_handler);
irq_set_chained_handler_and_data(irq, gpio_irq_handler,
(void *)gpio_irq);
}
/*--------------------------------------------------------------------------*/

View File

@ -182,9 +182,11 @@ static struct irq_chip bf537_mac_rx_irqchip = {
.irq_unmask = bf537_mac_rx_unmask_irq,
};
static void bf537_demux_mac_rx_irq(unsigned int int_irq,
static void bf537_demux_mac_rx_irq(unsigned int __int_irq,
struct irq_desc *desc)
{
unsigned int int_irq = irq_desc_get_irq(desc);
if (bfin_read_DMA1_IRQ_STATUS() & (DMA_DONE | DMA_ERR))
bfin_handle_irq(IRQ_MAC_RX);
else

View File

@ -194,7 +194,8 @@ void bfin_internal_unmask_irq(unsigned int irq)
#ifdef CONFIG_SMP
static void bfin_internal_unmask_irq_chip(struct irq_data *d)
{
bfin_internal_unmask_irq_affinity(d->irq, d->affinity);
bfin_internal_unmask_irq_affinity(d->irq,
irq_data_get_affinity_mask(d));
}
static int bfin_internal_set_affinity(struct irq_data *d,
@ -685,12 +686,12 @@ void bfin_demux_mac_status_irq(unsigned int int_err_irq,
}
#endif
static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle)
static inline void bfin_set_irq_handler(struct irq_data *d, irq_flow_handler_t handle)
{
#ifdef CONFIG_IPIPE
handle = handle_level_irq;
#endif
__irq_set_handler_locked(irq, handle);
irq_set_handler_locked(d, handle);
}
#ifdef CONFIG_GPIO_ADI
@ -802,9 +803,9 @@ static int bfin_gpio_irq_type(struct irq_data *d, unsigned int type)
}
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
bfin_set_irq_handler(irq, handle_edge_irq);
bfin_set_irq_handler(d, handle_edge_irq);
else
bfin_set_irq_handler(irq, handle_level_irq);
bfin_set_irq_handler(d, handle_level_irq);
return 0;
}
@ -824,9 +825,9 @@ static void bfin_demux_gpio_block(unsigned int irq)
}
}
void bfin_demux_gpio_irq(unsigned int inta_irq,
struct irq_desc *desc)
void bfin_demux_gpio_irq(unsigned int __inta_irq, struct irq_desc *desc)
{
unsigned int inta_irq = irq_desc_get_irq(desc);
unsigned int irq;
switch (inta_irq) {

View File

@ -93,10 +93,11 @@ static struct irq_chip megamod_chip = {
.irq_unmask = unmask_megamod,
};
static void megamod_irq_cascade(unsigned int irq, struct irq_desc *desc)
static void megamod_irq_cascade(unsigned int __irq, struct irq_desc *desc)
{
struct megamod_cascade_data *cascade;
struct megamod_pic *pic;
unsigned int irq;
u32 events;
int n, idx;
@ -282,8 +283,8 @@ static struct megamod_pic * __init init_megamod_pic(struct device_node *np)
soc_writel(~0, &pic->regs->evtmask[i]);
soc_writel(~0, &pic->regs->evtclr[i]);
irq_set_handler_data(irq, &cascade_data[i]);
irq_set_chained_handler(irq, megamod_irq_cascade);
irq_set_chained_handler_and_data(irq, megamod_irq_cascade,
&cascade_data[i]);
}
/* Finally, set up the MUX registers */

View File

@ -610,9 +610,9 @@ register_intr (unsigned int gsi, int irq, unsigned char delivery,
chip->name, irq_type->name);
chip = irq_type;
}
__irq_set_chip_handler_name_locked(irq, chip, trigger == IOSAPIC_EDGE ?
handle_edge_irq : handle_level_irq,
NULL);
irq_set_chip_handler_name_locked(irq_get_irq_data(irq), chip,
trigger == IOSAPIC_EDGE ? handle_edge_irq : handle_level_irq,
NULL);
return 0;
}
@ -838,7 +838,7 @@ iosapic_unregister_intr (unsigned int gsi)
if (iosapic_intr_info[irq].count == 0) {
#ifdef CONFIG_SMP
/* Clear affinity */
cpumask_setall(irq_get_irq_data(irq)->affinity);
cpumask_setall(irq_get_affinity_mask(irq));
#endif
/* Clear the interrupt information */
iosapic_intr_info[irq].dest = 0;

View File

@ -67,7 +67,7 @@ static char irq_redir [NR_IRQS]; // = { [0 ... NR_IRQS-1] = 1 };
void set_irq_affinity_info (unsigned int irq, int hwid, int redir)
{
if (irq < NR_IRQS) {
cpumask_copy(irq_get_irq_data(irq)->affinity,
cpumask_copy(irq_get_affinity_mask(irq),
cpumask_of(cpu_logical_id(hwid)));
irq_redir[irq] = (char) (redir & 0xff);
}
@ -119,8 +119,8 @@ static void migrate_irqs(void)
if (irqd_is_per_cpu(data))
continue;
if (cpumask_any_and(data->affinity, cpu_online_mask)
>= nr_cpu_ids) {
if (cpumask_any_and(irq_data_get_affinity_mask(data),
cpu_online_mask) >= nr_cpu_ids) {
/*
* Save it for phase 2 processing
*/

View File

@ -23,7 +23,7 @@ static int ia64_set_msi_irq_affinity(struct irq_data *idata,
if (irq_prepare_move(irq, cpu))
return -1;
__get_cached_msi_msg(idata->msi_desc, &msg);
__get_cached_msi_msg(irq_data_get_msi_desc(idata), &msg);
addr = msg.address_lo;
addr &= MSI_ADDR_DEST_ID_MASK;
@ -36,7 +36,7 @@ static int ia64_set_msi_irq_affinity(struct irq_data *idata,
msg.data = data;
pci_write_msi_msg(irq, &msg);
cpumask_copy(idata->affinity, cpumask_of(cpu));
cpumask_copy(irq_data_get_affinity_mask(idata), cpumask_of(cpu));
return 0;
}
@ -148,7 +148,7 @@ static int dmar_msi_set_affinity(struct irq_data *data,
msg.address_lo |= MSI_ADDR_DEST_ID_CPU(cpu_physical_id(cpu));
dmar_msi_write(irq, &msg);
cpumask_copy(data->affinity, mask);
cpumask_copy(irq_data_get_affinity_mask(data), mask);
return 0;
}

View File

@ -175,7 +175,7 @@ static int sn_set_msi_irq_affinity(struct irq_data *data,
* Release XIO resources for the old MSI PCI address
*/
__get_cached_msi_msg(data->msi_desc, &msg);
__get_cached_msi_msg(irq_data_get_msi_desc(data), &msg);
sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
pdev = sn_pdev->pdi_linux_pcidev;
provider = SN_PCIDEV_BUSPROVIDER(pdev);
@ -206,7 +206,7 @@ static int sn_set_msi_irq_affinity(struct irq_data *data,
msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);
pci_write_msi_msg(irq, &msg);
cpumask_copy(data->affinity, cpu_mask);
cpumask_copy(irq_data_get_affinity_mask(data), cpu_mask);
return 0;
}

View File

@ -143,8 +143,10 @@ static int intc_irq_set_type(struct irq_data *d, unsigned int type)
* We need to be careful with the masking/acking due to the side effects
* of masking an interrupt.
*/
static void intc_external_irq(unsigned int irq, struct irq_desc *desc)
static void intc_external_irq(unsigned int __irq, struct irq_desc *desc)
{
unsigned int irq = irq_desc_get_irq(desc);
irq_desc_get_chip(desc)->irq_ack(&desc->irq_data);
handle_simple_irq(irq, desc);
}

View File

@ -63,13 +63,15 @@ void __init oss_nubus_init(void)
* Handle miscellaneous OSS interrupts.
*/
static void oss_irq(unsigned int irq, struct irq_desc *desc)
static void oss_irq(unsigned int __irq, struct irq_desc *desc)
{
int events = oss->irq_pending &
(OSS_IP_IOPSCC | OSS_IP_SCSI | OSS_IP_IOPISM);
(OSS_IP_IOPSCC | OSS_IP_SCSI | OSS_IP_IOPISM);
#ifdef DEBUG_IRQS
if ((console_loglevel == 10) && !(events & OSS_IP_SCSI)) {
unsigned int irq = irq_desc_get_irq(desc);
printk("oss_irq: irq %u events = 0x%04X\n", irq,
(int) oss->irq_pending);
}

View File

@ -113,9 +113,10 @@ void __init psc_init(void)
* PSC interrupt handler. It's a lot like the VIA interrupt handler.
*/
static void psc_irq(unsigned int irq, struct irq_desc *desc)
static void psc_irq(unsigned int __irq, struct irq_desc *desc)
{
unsigned int offset = (unsigned int)irq_desc_get_handler_data(desc);
unsigned int irq = irq_desc_get_irq(desc);
int pIFR = pIFRbase + offset;
int pIER = pIERbase + offset;
int irq_num;

View File

@ -11,12 +11,11 @@
#include <linux/irqdomain.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include <linux/bug.h>
#include "../../drivers/irqchip/irqchip.h"
static void __iomem *intc_baseaddr;
/* No one else should require these constants, so define them locally here. */

View File

@ -1071,10 +1071,6 @@ config HOTPLUG_CPU
config SYS_SUPPORTS_HOTPLUG_CPU
bool
config I8259
bool
select IRQ_DOMAIN
config MIPS_BONITO64
bool

View File

@ -17,7 +17,6 @@
#include <linux/interrupt.h>
#include <linux/irqchip.h>
#include <linux/of_irq.h>
#include "../../../drivers/irqchip/irqchip.h"
#include <asm/irq_cpu.h>
#include <asm/mipsregs.h>

View File

@ -34,5 +34,5 @@ void __init arch_init_irq(void)
irqchip_init();
}
OF_DECLARE_2(irqchip, mips_cpu_intc, "mti,cpu-interrupt-controller",
IRQCHIP_DECLARE(mips_cpu_intc, "mti,cpu-interrupt-controller",
mips_cpu_irq_of_init);

View File

@ -61,7 +61,6 @@ obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o
obj-$(CONFIG_MIPS_VPE_APSP_API_CMP) += rtlx-cmp.o
obj-$(CONFIG_MIPS_VPE_APSP_API_MT) += rtlx-mt.o
obj-$(CONFIG_I8259) += i8259.o
obj-$(CONFIG_IRQ_CPU_RM7K) += irq-rm7000.o
obj-$(CONFIG_MIPS_MSC) += irq-msc01.o
obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o

View File

@ -200,7 +200,7 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
if (type == PCI_CAP_ID_MSI && nvec > 1)
return 1;
list_for_each_entry(entry, &dev->msi_list, list) {
for_each_pci_msi_entry(entry, dev) {
ret = arch_setup_msi_irq(dev, entry);
if (ret < 0)
return ret;

View File

@ -116,7 +116,7 @@ int __init init_clockevents(void)
{
struct irq_data *data;
data = irq_get_irq_data(cd->irq);
cpumask_copy(data->affinity, cpumask_of(cpu));
cpumask_copy(irq_data_get_affinity_mask(data), cpumask_of(cpu));
iact->flags |= IRQF_NOBALANCING;
}
#endif

View File

@ -87,7 +87,8 @@ static void mn10300_cpupic_mask_ack(struct irq_data *d)
tmp2 = GxICR(irq);
irq_affinity_online[irq] =
cpumask_any_and(d->affinity, cpu_online_mask);
cpumask_any_and(irq_data_get_affinity_mask(d),
cpu_online_mask);
CROSS_GxICR(irq, irq_affinity_online[irq]) =
(tmp & (GxICR_LEVEL | GxICR_ENABLE)) | GxICR_DETECT;
tmp = CROSS_GxICR(irq, irq_affinity_online[irq]);
@ -124,7 +125,7 @@ static void mn10300_cpupic_unmask_clear(struct irq_data *d)
} else {
tmp = GxICR(irq);
irq_affinity_online[irq] = cpumask_any_and(d->affinity,
irq_affinity_online[irq] = cpumask_any_and(irq_data_get_affinity_mask(d),
cpu_online_mask);
CROSS_GxICR(irq, irq_affinity_online[irq]) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT;
tmp = CROSS_GxICR(irq, irq_affinity_online[irq]);
@ -316,15 +317,16 @@ void migrate_irqs(void)
self = smp_processor_id();
for (irq = 0; irq < NR_IRQS; irq++) {
struct irq_data *data = irq_get_irq_data(irq);
struct cpumask *mask = irq_data_get_affinity_mask(data);
if (irqd_is_per_cpu(data))
continue;
if (cpumask_test_cpu(self, data->affinity) &&
if (cpumask_test_cpu(self, mask) &&
!cpumask_intersects(&irq_affinity[irq], cpu_online_mask)) {
int cpu_id;
cpu_id = cpumask_first(cpu_online_mask);
cpumask_set_cpu(cpu_id, data->affinity);
cpumask_set_cpu(cpu_id, mask);
}
/* We need to operate irq_affinity_online atomically. */
arch_local_cli_save(flags);
@ -335,8 +337,7 @@ void migrate_irqs(void)
GxICR(irq) = x & GxICR_LEVEL;
tmp = GxICR(irq);
new = cpumask_any_and(data->affinity,
cpu_online_mask);
new = cpumask_any_and(mask, cpu_online_mask);
irq_affinity_online[irq] = new;
CROSS_GxICR(irq, new) =

View File

@ -131,7 +131,7 @@ static int cpu_set_affinity_irq(struct irq_data *d, const struct cpumask *dest,
if (cpu_dest < 0)
return -1;
cpumask_copy(d->affinity, dest);
cpumask_copy(irq_data_get_affinity_mask(d), dest);
return 0;
}
@ -339,7 +339,7 @@ unsigned long txn_affinity_addr(unsigned int irq, int cpu)
{
#ifdef CONFIG_SMP
struct irq_data *d = irq_get_irq_data(irq);
cpumask_copy(d->affinity, cpumask_of(cpu));
cpumask_copy(irq_data_get_affinity_mask(d), cpumask_of(cpu));
#endif
return per_cpu(cpu_data, cpu).txn_addr;
@ -508,7 +508,7 @@ void do_cpu_irq_mask(struct pt_regs *regs)
unsigned long eirr_val;
int irq, cpu = smp_processor_id();
#ifdef CONFIG_SMP
struct irq_desc *desc;
struct irq_data *irq_data;
cpumask_t dest;
#endif
@ -522,9 +522,9 @@ void do_cpu_irq_mask(struct pt_regs *regs)
irq = eirr_to_irq(eirr_val);
#ifdef CONFIG_SMP
desc = irq_to_desc(irq);
cpumask_copy(&dest, desc->irq_data.affinity);
if (irqd_is_per_cpu(&desc->irq_data) &&
irq_data = irq_get_irq_data(irq);
cpumask_copy(&dest, irq_data_get_affinity_mask(irq_data));
if (irqd_is_per_cpu(irq_data) &&
!cpumask_test_cpu(smp_processor_id(), &dest)) {
int cpu = cpumask_first(&dest);

View File

@ -123,7 +123,8 @@ cpld_pic_cascade(unsigned int irq, struct irq_desc *desc)
}
static int
cpld_pic_host_match(struct irq_domain *h, struct device_node *node)
cpld_pic_host_match(struct irq_domain *h, struct device_node *node,
enum irq_domain_bus_token bus_token)
{
return cpld_pic_node == node;
}

View File

@ -213,7 +213,7 @@ static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg)
return -ENODEV;
}
entry = list_first_entry(&dev->msi_list, struct msi_desc, list);
entry = first_pci_msi_entry(dev);
for (; dn; dn = of_get_next_parent(dn)) {
if (entry->msi_attrib.is_64) {
@ -269,7 +269,7 @@ static int axon_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
if (rc)
return rc;
list_for_each_entry(entry, &dev->msi_list, list) {
for_each_pci_msi_entry(entry, dev) {
virq = irq_create_direct_mapping(msic->irq_domain);
if (virq == NO_IRQ) {
dev_warn(&dev->dev,
@ -292,7 +292,7 @@ static void axon_msi_teardown_msi_irqs(struct pci_dev *dev)
dev_dbg(&dev->dev, "axon_msi: tearing down msi irqs\n");
list_for_each_entry(entry, &dev->msi_list, list) {
for_each_pci_msi_entry(entry, dev) {
if (entry->irq == NO_IRQ)
continue;

View File

@ -222,7 +222,8 @@ void iic_request_IPIs(void)
#endif /* CONFIG_SMP */
static int iic_host_match(struct irq_domain *h, struct device_node *node)
static int iic_host_match(struct irq_domain *h, struct device_node *node,
enum irq_domain_bus_token bus_token)
{
return of_device_is_compatible(node,
"IBM,CBEA-Internal-Interrupt-Controller");

View File

@ -108,7 +108,8 @@ static int flipper_pic_map(struct irq_domain *h, unsigned int virq,
return 0;
}
static int flipper_pic_match(struct irq_domain *h, struct device_node *np)
static int flipper_pic_match(struct irq_domain *h, struct device_node *np,
enum irq_domain_bus_token bus_token)
{
return 1;
}

View File

@ -66,7 +66,7 @@ static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev)
pr_debug("pasemi_msi_teardown_msi_irqs, pdev %p\n", pdev);
list_for_each_entry(entry, &pdev->msi_list, list) {
for_each_pci_msi_entry(entry, pdev) {
if (entry->irq == NO_IRQ)
continue;
@ -94,7 +94,7 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
msg.address_hi = 0;
msg.address_lo = PASEMI_MSI_ADDR;
list_for_each_entry(entry, &pdev->msi_list, list) {
for_each_pci_msi_entry(entry, pdev) {
/* Allocate 16 interrupts for now, since that's the grouping for
* affinity. This can be changed later if it turns out 32 is too
* few MSIs for someone, but restrictions will apply to how the

View File

@ -268,7 +268,8 @@ static struct irqaction gatwick_cascade_action = {
.name = "cascade",
};
static int pmac_pic_host_match(struct irq_domain *h, struct device_node *node)
static int pmac_pic_host_match(struct irq_domain *h, struct device_node *node,
enum irq_domain_bus_token bus_token)
{
/* We match all, we don't always have a node anyway */
return 1;

View File

@ -134,7 +134,8 @@ static void opal_handle_irq_work(struct irq_work *work)
opal_handle_events(be64_to_cpu(last_outstanding_events));
}
static int opal_event_match(struct irq_domain *h, struct device_node *node)
static int opal_event_match(struct irq_domain *h, struct device_node *node,
enum irq_domain_bus_token bus_token)
{
return h->of_node == node;
}

View File

@ -61,7 +61,7 @@ int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
if (pdev->no_64bit_msi && !phb->msi32_support)
return -ENODEV;
list_for_each_entry(entry, &pdev->msi_list, list) {
for_each_pci_msi_entry(entry, pdev) {
if (!entry->msi_attrib.is_64 && !phb->msi32_support) {
pr_warn("%s: Supports only 64-bit MSIs\n",
pci_name(pdev));
@ -103,7 +103,7 @@ void pnv_teardown_msi_irqs(struct pci_dev *pdev)
if (WARN_ON(!phb))
return;
list_for_each_entry(entry, &pdev->msi_list, list) {
for_each_pci_msi_entry(entry, pdev) {
if (entry->irq == NO_IRQ)
continue;
irq_set_msi_desc(entry->irq, NULL);

View File

@ -678,7 +678,8 @@ static int ps3_host_map(struct irq_domain *h, unsigned int virq,
return 0;
}
static int ps3_host_match(struct irq_domain *h, struct device_node *np)
static int ps3_host_match(struct irq_domain *h, struct device_node *np,
enum irq_domain_bus_token bus_token)
{
/* Match all */
return 1;

View File

@ -118,7 +118,7 @@ static void rtas_teardown_msi_irqs(struct pci_dev *pdev)
{
struct msi_desc *entry;
list_for_each_entry(entry, &pdev->msi_list, list) {
for_each_pci_msi_entry(entry, pdev) {
if (entry->irq == NO_IRQ)
continue;
@ -350,7 +350,7 @@ static int check_msix_entries(struct pci_dev *pdev)
* So we must reject such requests. */
expected = 0;
list_for_each_entry(entry, &pdev->msi_list, list) {
for_each_pci_msi_entry(entry, pdev) {
if (entry->msi_attrib.entry_nr != expected) {
pr_debug("rtas_msi: bad MSI-X entries.\n");
return -EINVAL;
@ -462,7 +462,7 @@ again:
}
i = 0;
list_for_each_entry(entry, &pdev->msi_list, list) {
for_each_pci_msi_entry(entry, pdev) {
hwirq = rtas_query_irq_number(pdn, i++);
if (hwirq < 0) {
pr_debug("rtas_msi: error (%d) getting hwirq\n", rc);

View File

@ -177,7 +177,8 @@ unsigned int ehv_pic_get_irq(void)
return irq_linear_revmap(global_ehv_pic->irqhost, irq);
}
static int ehv_pic_host_match(struct irq_domain *h, struct device_node *node)
static int ehv_pic_host_match(struct irq_domain *h, struct device_node *node,
enum irq_domain_bus_token bus_token)
{
/* Exact match, unless ehv_pic node is NULL */
return h->of_node == NULL || h->of_node == node;

View File

@ -129,7 +129,7 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev)
struct msi_desc *entry;
struct fsl_msi *msi_data;
list_for_each_entry(entry, &pdev->msi_list, list) {
for_each_pci_msi_entry(entry, pdev) {
if (entry->irq == NO_IRQ)
continue;
msi_data = irq_get_chip_data(entry->irq);
@ -219,7 +219,7 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
}
}
list_for_each_entry(entry, &pdev->msi_list, list) {
for_each_pci_msi_entry(entry, pdev) {
/*
* Loop over all the MSI devices until we find one that has an
* available interrupt.

View File

@ -162,7 +162,8 @@ static struct resource pic_edgectrl_iores = {
.flags = IORESOURCE_BUSY,
};
static int i8259_host_match(struct irq_domain *h, struct device_node *node)
static int i8259_host_match(struct irq_domain *h, struct device_node *node,
enum irq_domain_bus_token bus_token)
{
return h->of_node == NULL || h->of_node == node;
}

View File

@ -671,7 +671,8 @@ static struct irq_chip ipic_edge_irq_chip = {
.irq_set_type = ipic_set_irq_type,
};
static int ipic_host_match(struct irq_domain *h, struct device_node *node)
static int ipic_host_match(struct irq_domain *h, struct device_node *node,
enum irq_domain_bus_token bus_token)
{
/* Exact match, unless ipic node is NULL */
return h->of_node == NULL || h->of_node == node;

View File

@ -1007,7 +1007,8 @@ static struct irq_chip mpic_irq_ht_chip = {
#endif /* CONFIG_MPIC_U3_HT_IRQS */
static int mpic_host_match(struct irq_domain *h, struct device_node *node)
static int mpic_host_match(struct irq_domain *h, struct device_node *node,
enum irq_domain_bus_token bus_token)
{
/* Exact match, unless mpic node is NULL */
return h->of_node == NULL || h->of_node == node;

View File

@ -108,7 +108,7 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev)
{
struct msi_desc *entry;
list_for_each_entry(entry, &pdev->msi_list, list) {
for_each_pci_msi_entry(entry, pdev) {
if (entry->irq == NO_IRQ)
continue;
@ -140,7 +140,7 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
return -ENXIO;
}
list_for_each_entry(entry, &pdev->msi_list, list) {
for_each_pci_msi_entry(entry, pdev) {
hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap, 1);
if (hwirq < 0) {
pr_debug("u3msi: failed allocating hwirq\n");

View File

@ -51,7 +51,7 @@ static int hsta_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
return -EINVAL;
}
list_for_each_entry(entry, &dev->msi_list, list) {
for_each_pci_msi_entry(entry, dev) {
irq = msi_bitmap_alloc_hwirqs(&ppc4xx_hsta_msi.bmp, 1);
if (irq < 0) {
pr_debug("%s: Failed to allocate msi interrupt\n",
@ -109,7 +109,7 @@ static void hsta_teardown_msi_irqs(struct pci_dev *dev)
struct msi_desc *entry;
int irq;
list_for_each_entry(entry, &dev->msi_list, list) {
for_each_pci_msi_entry(entry, dev) {
if (entry->irq == NO_IRQ)
continue;

View File

@ -93,7 +93,7 @@ static int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
if (!msi_data->msi_virqs)
return -ENOMEM;
list_for_each_entry(entry, &dev->msi_list, list) {
for_each_pci_msi_entry(entry, dev) {
int_no = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
if (int_no >= 0)
break;
@ -127,7 +127,7 @@ void ppc4xx_teardown_msi_irqs(struct pci_dev *dev)
dev_dbg(&dev->dev, "PCIE-MSI: tearing down msi irqs\n");
list_for_each_entry(entry, &dev->msi_list, list) {
for_each_pci_msi_entry(entry, dev) {
if (entry->irq == NO_IRQ)
continue;
irq_set_msi_desc(entry->irq, NULL);

View File

@ -244,7 +244,8 @@ static struct irq_chip qe_ic_irq_chip = {
.irq_mask_ack = qe_ic_mask_irq,
};
static int qe_ic_host_match(struct irq_domain *h, struct device_node *node)
static int qe_ic_host_match(struct irq_domain *h, struct device_node *node,
enum irq_domain_bus_token bus_token)
{
/* Exact match, unless qe_ic node is NULL */
return h->of_node == NULL || h->of_node == node;

View File

@ -72,7 +72,7 @@ static unsigned int ics_opal_startup(struct irq_data *d)
* card, using the MSI mask bits. Firmware doesn't appear to unmask
* at that level, so we do it here by hand.
*/
if (d->msi_desc)
if (irq_data_get_msi_desc(d))
pci_msi_unmask_irq(d);
#endif

View File

@ -75,7 +75,7 @@ static unsigned int ics_rtas_startup(struct irq_data *d)
* card, using the MSI mask bits. Firmware doesn't appear to unmask
* at that level, so we do it here by hand.
*/
if (d->msi_desc)
if (irq_data_get_msi_desc(d))
pci_msi_unmask_irq(d);
#endif
/* unmask it */

View File

@ -298,7 +298,8 @@ int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask,
}
#endif /* CONFIG_SMP */
static int xics_host_match(struct irq_domain *h, struct device_node *node)
static int xics_host_match(struct irq_domain *h, struct device_node *node,
enum irq_domain_bus_token bus_token)
{
struct ics *ics;

View File

@ -409,7 +409,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
/* Request MSI interrupts */
hwirq = 0;
list_for_each_entry(msi, &pdev->msi_list, list) {
for_each_pci_msi_entry(msi, pdev) {
rc = -EIO;
irq = irq_alloc_desc(0); /* Alloc irq on node 0 */
if (irq < 0)
@ -435,7 +435,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
return (msi_vecs == nvec) ? 0 : msi_vecs;
out_msi:
list_for_each_entry(msi, &pdev->msi_list, list) {
for_each_pci_msi_entry(msi, pdev) {
if (hwirq-- == 0)
break;
irq_set_msi_desc(msi->irq, NULL);
@ -465,7 +465,7 @@ void arch_teardown_msi_irqs(struct pci_dev *pdev)
return;
/* Release MSI interrupts */
list_for_each_entry(msi, &pdev->msi_list, list) {
for_each_pci_msi_entry(msi, pdev) {
if (msi->msi_attrib.is_msix)
__pci_msix_desc_mask_irq(msi, 1);
else

View File

@ -31,7 +31,7 @@ struct irq_domain *se7343_irq_domain;
static void se7343_irq_demux(unsigned int irq, struct irq_desc *desc)
{
struct irq_data *data = irq_get_irq_data(irq);
struct irq_data *data = irq_desc_get_irq_data(desc);
struct irq_chip *chip = irq_data_get_irq_chip(data);
unsigned long mask;
int bit;

View File

@ -30,7 +30,7 @@ struct irq_domain *se7722_irq_domain;
static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc)
{
struct irq_data *data = irq_get_irq_data(irq);
struct irq_data *data = irq_desc_get_irq_data(desc);
struct irq_chip *chip = irq_data_get_irq_chip(data);
unsigned long mask;
int bit;

View File

@ -92,8 +92,9 @@ static struct irq_chip se7724_irq_chip __read_mostly = {
.irq_unmask = enable_se7724_irq,
};
static void se7724_irq_demux(unsigned int irq, struct irq_desc *desc)
static void se7724_irq_demux(unsigned int __irq, struct irq_desc *desc)
{
unsigned int irq = irq_desc_get_irq(desc);
struct fpga_irq set = get_fpga_irq(irq);
unsigned short intv = __raw_readw(set.sraddr);
unsigned int ext_irq = set.base;

View File

@ -62,7 +62,7 @@ static int x3proto_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
static void x3proto_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
{
struct irq_data *data = irq_get_irq_data(irq);
struct irq_data *data = irq_desc_get_irq_data(desc);
struct irq_chip *chip = irq_data_get_irq_chip(data);
unsigned long mask;
int pin;

View File

@ -227,16 +227,17 @@ void migrate_irqs(void)
for_each_active_irq(irq) {
struct irq_data *data = irq_get_irq_data(irq);
if (data->node == cpu) {
unsigned int newcpu = cpumask_any_and(data->affinity,
if (irq_data_get_node(data) == cpu) {
struct cpumask *mask = irq_data_get_affinity_mask(data);
unsigned int newcpu = cpumask_any_and(mask,
cpu_online_mask);
if (newcpu >= nr_cpu_ids) {
pr_info_ratelimited("IRQ%u no longer affine to CPU%u\n",
irq, cpu);
cpumask_setall(data->affinity);
cpumask_setall(mask);
}
irq_set_affinity(irq, data->affinity);
irq_set_affinity(irq, mask);
}
}
}

View File

@ -210,21 +210,21 @@ struct irq_handler_data {
static inline unsigned int irq_data_to_handle(struct irq_data *data)
{
struct irq_handler_data *ihd = data->handler_data;
struct irq_handler_data *ihd = irq_data_get_irq_handler_data(data);
return ihd->dev_handle;
}
static inline unsigned int irq_data_to_ino(struct irq_data *data)
{
struct irq_handler_data *ihd = data->handler_data;
struct irq_handler_data *ihd = irq_data_get_irq_handler_data(data);
return ihd->dev_ino;
}
static inline unsigned long irq_data_to_sysino(struct irq_data *data)
{
struct irq_handler_data *ihd = data->handler_data;
struct irq_handler_data *ihd = irq_data_get_irq_handler_data(data);
return ihd->sysino;
}
@ -370,13 +370,15 @@ static int irq_choose_cpu(unsigned int irq, const struct cpumask *affinity)
static void sun4u_irq_enable(struct irq_data *data)
{
struct irq_handler_data *handler_data = data->handler_data;
struct irq_handler_data *handler_data;
handler_data = irq_data_get_irq_handler_data(data);
if (likely(handler_data)) {
unsigned long cpuid, imap, val;
unsigned int tid;
cpuid = irq_choose_cpu(data->irq, data->affinity);
cpuid = irq_choose_cpu(data->irq,
irq_data_get_affinity_mask(data));
imap = handler_data->imap;
tid = sun4u_compute_tid(imap, cpuid);
@ -393,8 +395,9 @@ static void sun4u_irq_enable(struct irq_data *data)
static int sun4u_set_affinity(struct irq_data *data,
const struct cpumask *mask, bool force)
{
struct irq_handler_data *handler_data = data->handler_data;
struct irq_handler_data *handler_data;
handler_data = irq_data_get_irq_handler_data(data);
if (likely(handler_data)) {
unsigned long cpuid, imap, val;
unsigned int tid;
@ -438,15 +441,17 @@ static void sun4u_irq_disable(struct irq_data *data)
static void sun4u_irq_eoi(struct irq_data *data)
{
struct irq_handler_data *handler_data = data->handler_data;
struct irq_handler_data *handler_data;
handler_data = irq_data_get_irq_handler_data(data);
if (likely(handler_data))
upa_writeq(ICLR_IDLE, handler_data->iclr);
}
static void sun4v_irq_enable(struct irq_data *data)
{
unsigned long cpuid = irq_choose_cpu(data->irq, data->affinity);
unsigned long cpuid = irq_choose_cpu(data->irq,
irq_data_get_affinity_mask(data));
unsigned int ino = irq_data_to_sysino(data);
int err;
@ -508,7 +513,7 @@ static void sun4v_virq_enable(struct irq_data *data)
unsigned long cpuid;
int err;
cpuid = irq_choose_cpu(data->irq, data->affinity);
cpuid = irq_choose_cpu(data->irq, irq_data_get_affinity_mask(data));
err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
if (err != HV_EOK)
@ -881,8 +886,8 @@ void fixup_irqs(void)
if (desc->action && !irqd_is_per_cpu(data)) {
if (data->chip->irq_set_affinity)
data->chip->irq_set_affinity(data,
data->affinity,
false);
irq_data_get_affinity_mask(data),
false);
}
raw_spin_unlock_irqrestore(&desc->lock, flags);
}

View File

@ -126,7 +126,7 @@ static int leon_set_affinity(struct irq_data *data, const struct cpumask *dest,
int oldcpu, newcpu;
mask = (unsigned long)data->chip_data;
oldcpu = irq_choose_cpu(data->affinity);
oldcpu = irq_choose_cpu(irq_data_get_affinity_mask(data));
newcpu = irq_choose_cpu(dest);
if (oldcpu == newcpu)
@ -149,7 +149,7 @@ static void leon_unmask_irq(struct irq_data *data)
int cpu;
mask = (unsigned long)data->chip_data;
cpu = irq_choose_cpu(data->affinity);
cpu = irq_choose_cpu(irq_data_get_affinity_mask(data));
spin_lock_irqsave(&leon_irq_lock, flags);
oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(cpu));
LEON3_BYPASS_STORE_PA(LEON_IMASK(cpu), (oldmask | mask));
@ -162,7 +162,7 @@ static void leon_mask_irq(struct irq_data *data)
int cpu;
mask = (unsigned long)data->chip_data;
cpu = irq_choose_cpu(data->affinity);
cpu = irq_choose_cpu(irq_data_get_affinity_mask(data));
spin_lock_irqsave(&leon_irq_lock, flags);
oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(cpu));
LEON3_BYPASS_STORE_PA(LEON_IMASK(cpu), (oldmask & ~mask));

View File

@ -914,7 +914,7 @@ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
void arch_teardown_msi_irq(unsigned int irq)
{
struct msi_desc *entry = irq_get_msi_desc(irq);
struct pci_dev *pdev = entry->dev;
struct pci_dev *pdev = msi_desc_to_pci_dev(entry);
struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
if (pbm->teardown_msi_irq)

View File

@ -188,7 +188,7 @@ void sun4d_handler_irq(unsigned int pil, struct pt_regs *regs)
static void sun4d_mask_irq(struct irq_data *data)
{
struct sun4d_handler_data *handler_data = data->handler_data;
struct sun4d_handler_data *handler_data = irq_data_get_irq_handler_data(data);
unsigned int real_irq;
#ifdef CONFIG_SMP
int cpuid = handler_data->cpuid;
@ -206,7 +206,7 @@ static void sun4d_mask_irq(struct irq_data *data)
static void sun4d_unmask_irq(struct irq_data *data)
{
struct sun4d_handler_data *handler_data = data->handler_data;
struct sun4d_handler_data *handler_data = irq_data_get_irq_handler_data(data);
unsigned int real_irq;
#ifdef CONFIG_SMP
int cpuid = handler_data->cpuid;

View File

@ -188,9 +188,10 @@ static unsigned long sun4m_imask[0x50] = {
static void sun4m_mask_irq(struct irq_data *data)
{
struct sun4m_handler_data *handler_data = data->handler_data;
struct sun4m_handler_data *handler_data;
int cpu = smp_processor_id();
handler_data = irq_data_get_irq_handler_data(data);
if (handler_data->mask) {
unsigned long flags;
@ -206,9 +207,10 @@ static void sun4m_mask_irq(struct irq_data *data)
static void sun4m_unmask_irq(struct irq_data *data)
{
struct sun4m_handler_data *handler_data = data->handler_data;
struct sun4m_handler_data *handler_data;
int cpu = smp_processor_id();
handler_data = irq_data_get_irq_handler_data(data);
if (handler_data->mask) {
unsigned long flags;

View File

@ -304,11 +304,12 @@ static struct irq_chip tilegx_legacy_irq_chip = {
* to Linux which just calls handle_level_irq() after clearing the
* MAC INTx Assert status bit associated with this interrupt.
*/
static void trio_handle_level_irq(unsigned int irq, struct irq_desc *desc)
static void trio_handle_level_irq(unsigned int __irq, struct irq_desc *desc)
{
struct pci_controller *controller = irq_desc_get_handler_data(desc);
gxio_trio_context_t *trio_context = controller->trio;
uint64_t intx = (uint64_t)irq_desc_get_chip_data(desc);
unsigned int irq = irq_desc_get_irq(desc);
int mac = controller->mac;
unsigned int reg_offset;
uint64_t level_mask;
@ -1442,7 +1443,7 @@ static struct pci_ops tile_cfg_ops = {
/* MSI support starts here. */
static unsigned int tilegx_msi_startup(struct irq_data *d)
{
if (d->msi_desc)
if (irq_data_get_msi_desc(d))
pci_msi_unmask_irq(d);
return 0;

View File

@ -112,10 +112,9 @@ static struct irq_chip puv3_low_gpio_chip = {
* irq_controller_lock held, and IRQs disabled. Decode the IRQ
* and call the handler.
*/
static void
puv3_gpio_handler(unsigned int irq, struct irq_desc *desc)
static void puv3_gpio_handler(unsigned int __irq, struct irq_desc *desc)
{
unsigned int mask;
unsigned int mask, irq;
mask = readl(GPIO_GEDR);
do {

View File

@ -179,7 +179,7 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
if (ret)
goto error;
i = 0;
list_for_each_entry(msidesc, &dev->msi_list, list) {
for_each_pci_msi_entry(msidesc, dev) {
irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i],
(type == PCI_CAP_ID_MSI) ? nvec : 1,
(type == PCI_CAP_ID_MSIX) ?
@ -230,7 +230,7 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
if (type == PCI_CAP_ID_MSI && nvec > 1)
return 1;
list_for_each_entry(msidesc, &dev->msi_list, list) {
for_each_pci_msi_entry(msidesc, dev) {
__pci_read_msi_msg(msidesc, &msg);
pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) |
((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff);
@ -274,7 +274,7 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
int ret = 0;
struct msi_desc *msidesc;
list_for_each_entry(msidesc, &dev->msi_list, list) {
for_each_pci_msi_entry(msidesc, dev) {
struct physdev_map_pirq map_irq;
domid_t domid;
@ -386,7 +386,7 @@ static void xen_teardown_msi_irqs(struct pci_dev *dev)
{
struct msi_desc *msidesc;
msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
msidesc = first_pci_msi_entry(dev);
if (msidesc->msi_attrib.is_msix)
xen_pci_frontend_disable_msix(dev);
else

View File

@ -177,23 +177,25 @@ void migrate_irqs(void)
for_each_active_irq(i) {
struct irq_data *data = irq_get_irq_data(i);
struct cpumask *mask;
unsigned int newcpu;
if (irqd_is_per_cpu(data))
continue;
if (!cpumask_test_cpu(cpu, data->affinity))
mask = irq_data_get_affinity_mask(data);
if (!cpumask_test_cpu(cpu, mask))
continue;
newcpu = cpumask_any_and(data->affinity, cpu_online_mask);
newcpu = cpumask_any_and(mask, cpu_online_mask);
if (newcpu >= nr_cpu_ids) {
pr_info_ratelimited("IRQ%u no longer affine to CPU%u\n",
i, cpu);
cpumask_setall(data->affinity);
cpumask_setall(mask);
}
irq_set_affinity(i, data->affinity);
irq_set_affinity(i, mask);
}
}
#endif /* CONFIG_HOTPLUG_CPU */

View File

@ -22,6 +22,7 @@ obj-$(CONFIG_REGMAP) += regmap/
obj-$(CONFIG_SOC_BUS) += soc.o
obj-$(CONFIG_PINCTRL) += pinctrl.o
obj-$(CONFIG_DEV_COREDUMP) += devcoredump.o
obj-$(CONFIG_GENERIC_MSI_IRQ_DOMAIN) += platform-msi.o
ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG

View File

@ -708,6 +708,9 @@ void device_initialize(struct device *dev)
INIT_LIST_HEAD(&dev->devres_head);
device_pm_init(dev);
set_dev_node(dev, -1);
#ifdef CONFIG_GENERIC_MSI_IRQ
INIT_LIST_HEAD(&dev->msi_list);
#endif
}
EXPORT_SYMBOL_GPL(device_initialize);

282
drivers/base/platform-msi.c Normal file
View File

@ -0,0 +1,282 @@
/*
* MSI framework for platform devices
*
* Copyright (C) 2015 ARM Limited, All Rights Reserved.
* Author: Marc Zyngier <marc.zyngier@arm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/device.h>
#include <linux/idr.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/msi.h>
#include <linux/slab.h>
#define DEV_ID_SHIFT 24
/*
* Internal data structure containing a (made up, but unique) devid
* and the callback to write the MSI message.
*/
struct platform_msi_priv_data {
irq_write_msi_msg_t write_msg;
int devid;
};
/* The devid allocator */
static DEFINE_IDA(platform_msi_devid_ida);
#ifdef GENERIC_MSI_DOMAIN_OPS
/*
* Convert an msi_desc to a globaly unique identifier (per-device
* devid + msi_desc position in the msi_list).
*/
static irq_hw_number_t platform_msi_calc_hwirq(struct msi_desc *desc)
{
u32 devid;
devid = desc->platform.msi_priv_data->devid;
return (devid << (32 - DEV_ID_SHIFT)) | desc->platform.msi_index;
}
static void platform_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
{
arg->desc = desc;
arg->hwirq = platform_msi_calc_hwirq(desc);
}
static int platform_msi_init(struct irq_domain *domain,
struct msi_domain_info *info,
unsigned int virq, irq_hw_number_t hwirq,
msi_alloc_info_t *arg)
{
struct irq_data *data;
irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
info->chip, info->chip_data);
/*
* Save the MSI descriptor in handler_data so that the
* irq_write_msi_msg callback can retrieve it (and the
* associated device).
*/
data = irq_domain_get_irq_data(domain, virq);
data->handler_data = arg->desc;
return 0;
}
#else
#define platform_msi_set_desc NULL
#define platform_msi_init NULL
#endif
static void platform_msi_update_dom_ops(struct msi_domain_info *info)
{
struct msi_domain_ops *ops = info->ops;
BUG_ON(!ops);
if (ops->msi_init == NULL)
ops->msi_init = platform_msi_init;
if (ops->set_desc == NULL)
ops->set_desc = platform_msi_set_desc;
}
static void platform_msi_write_msg(struct irq_data *data, struct msi_msg *msg)
{
struct msi_desc *desc = irq_data_get_irq_handler_data(data);
struct platform_msi_priv_data *priv_data;
priv_data = desc->platform.msi_priv_data;
priv_data->write_msg(desc, msg);
}
static void platform_msi_update_chip_ops(struct msi_domain_info *info)
{
struct irq_chip *chip = info->chip;
BUG_ON(!chip);
if (!chip->irq_mask)
chip->irq_mask = irq_chip_mask_parent;
if (!chip->irq_unmask)
chip->irq_unmask = irq_chip_unmask_parent;
if (!chip->irq_eoi)
chip->irq_eoi = irq_chip_eoi_parent;
if (!chip->irq_set_affinity)
chip->irq_set_affinity = msi_domain_set_affinity;
if (!chip->irq_write_msi_msg)
chip->irq_write_msi_msg = platform_msi_write_msg;
}
static void platform_msi_free_descs(struct device *dev)
{
struct msi_desc *desc, *tmp;
list_for_each_entry_safe(desc, tmp, dev_to_msi_list(dev), list) {
list_del(&desc->list);
free_msi_entry(desc);
}
}
static int platform_msi_alloc_descs(struct device *dev, int nvec,
struct platform_msi_priv_data *data)
{
int i;
for (i = 0; i < nvec; i++) {
struct msi_desc *desc;
desc = alloc_msi_entry(dev);
if (!desc)
break;
desc->platform.msi_priv_data = data;
desc->platform.msi_index = i;
desc->nvec_used = 1;
list_add_tail(&desc->list, dev_to_msi_list(dev));
}
if (i != nvec) {
/* Clean up the mess */
platform_msi_free_descs(dev);
return -ENOMEM;
}
return 0;
}
/**
* platform_msi_create_irq_domain - Create a platform MSI interrupt domain
* @np: Optional device-tree node of the interrupt controller
* @info: MSI domain info
* @parent: Parent irq domain
*
* Updates the domain and chip ops and creates a platform MSI
* interrupt domain.
*
* Returns:
* A domain pointer or NULL in case of failure.
*/
struct irq_domain *platform_msi_create_irq_domain(struct device_node *np,
struct msi_domain_info *info,
struct irq_domain *parent)
{
struct irq_domain *domain;
if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS)
platform_msi_update_dom_ops(info);
if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
platform_msi_update_chip_ops(info);
domain = msi_create_irq_domain(np, info, parent);
if (domain)
domain->bus_token = DOMAIN_BUS_PLATFORM_MSI;
return domain;
}
/**
* platform_msi_domain_alloc_irqs - Allocate MSI interrupts for @dev
* @dev: The device for which to allocate interrupts
* @nvec: The number of interrupts to allocate
* @write_msi_msg: Callback to write an interrupt message for @dev
*
* Returns:
* Zero for success, or an error code in case of failure
*/
int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
irq_write_msi_msg_t write_msi_msg)
{
struct platform_msi_priv_data *priv_data;
int err;
/*
* Limit the number of interrupts to 256 per device. Should we
* need to bump this up, DEV_ID_SHIFT should be adjusted
* accordingly (which would impact the max number of MSI
* capable devices).
*/
if (!dev->msi_domain || !write_msi_msg || !nvec ||
nvec > (1 << (32 - DEV_ID_SHIFT)))
return -EINVAL;
if (dev->msi_domain->bus_token != DOMAIN_BUS_PLATFORM_MSI) {
dev_err(dev, "Incompatible msi_domain, giving up\n");
return -EINVAL;
}
/* Already had a helping of MSI? Greed... */
if (!list_empty(dev_to_msi_list(dev)))
return -EBUSY;
priv_data = kzalloc(sizeof(*priv_data), GFP_KERNEL);
if (!priv_data)
return -ENOMEM;
priv_data->devid = ida_simple_get(&platform_msi_devid_ida,
0, 1 << DEV_ID_SHIFT, GFP_KERNEL);
if (priv_data->devid < 0) {
err = priv_data->devid;
goto out_free_data;
}
priv_data->write_msg = write_msi_msg;
err = platform_msi_alloc_descs(dev, nvec, priv_data);
if (err)
goto out_free_id;
err = msi_domain_alloc_irqs(dev->msi_domain, dev, nvec);
if (err)
goto out_free_desc;
return 0;
out_free_desc:
platform_msi_free_descs(dev);
out_free_id:
ida_simple_remove(&platform_msi_devid_ida, priv_data->devid);
out_free_data:
kfree(priv_data);
return err;
}
/**
* platform_msi_domain_free_irqs - Free MSI interrupts for @dev
* @dev: The device for which to free interrupts
*/
void platform_msi_domain_free_irqs(struct device *dev)
{
struct msi_desc *desc;
desc = first_msi_entry(dev);
if (desc) {
struct platform_msi_priv_data *data;
data = desc->platform.msi_priv_data;
ida_simple_remove(&platform_msi_devid_ida, data->devid);
kfree(data);
}
msi_domain_free_irqs(dev->msi_domain, dev);
platform_msi_free_descs(dev);
}

View File

@ -61,6 +61,10 @@ config ATMEL_AIC5_IRQ
select MULTI_IRQ_HANDLER
select SPARSE_IRQ
config I8259
bool
select IRQ_DOMAIN
config BCM7038_L1_IRQ
bool
select GENERIC_IRQ_CHIP
@ -177,3 +181,9 @@ config RENESAS_H8300H_INTC
config RENESAS_H8S_INTC
bool
select IRQ_DOMAIN
config IMX_GPCV2
bool
select IRQ_DOMAIN
help
Enables the wakeup IRQs for IMX platforms with GPCv2 block

View File

@ -1,6 +1,7 @@
obj-$(CONFIG_IRQCHIP) += irqchip.o
obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o
obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2836.o
obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o
obj-$(CONFIG_ARCH_HIP04) += irq-hip04.o
obj-$(CONFIG_ARCH_MMP) += irq-mmp.o
@ -22,11 +23,12 @@ obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o
obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o
obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-common.o
obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o
obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
obj-$(CONFIG_ARM_VIC) += irq-vic.o
obj-$(CONFIG_ATMEL_AIC_IRQ) += irq-atmel-aic-common.o irq-atmel-aic.o
obj-$(CONFIG_ATMEL_AIC5_IRQ) += irq-atmel-aic-common.o irq-atmel-aic5.o
obj-$(CONFIG_I8259) += irq-i8259.o
obj-$(CONFIG_IMGPDC_IRQ) += irq-imgpdc.o
obj-$(CONFIG_IRQ_MIPS_CPU) += irq-mips-cpu.o
obj-$(CONFIG_SIRF_IRQ) += irq-sirfsoc.o
@ -52,3 +54,4 @@ obj-$(CONFIG_RENESAS_H8300H_INTC) += irq-renesas-h8300h.o
obj-$(CONFIG_RENESAS_H8S_INTC) += irq-renesas-h8s.o
obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o
obj-$(CONFIG_INGENIC_IRQ) += irq-ingenic.o
obj-$(CONFIG_IMX_GPCV2) += irq-imx-gpcv2.o

View File

@ -15,13 +15,12 @@
#include <linux/slab.h>
#include <linux/syscore_ops.h>
#include <linux/irqdomain.h>
#include <linux/irqchip.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/interrupt.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include "irqchip.h"
#define COMBINER_ENABLE_SET 0x0
#define COMBINER_ENABLE_CLEAR 0x4
#define COMBINER_INT_STATUS 0xC
@ -66,10 +65,12 @@ static void combiner_unmask_irq(struct irq_data *data)
__raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
}
static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
static void combiner_handle_cascade_irq(unsigned int __irq,
struct irq_desc *desc)
{
struct combiner_chip_data *chip_data = irq_get_handler_data(irq);
struct irq_chip *chip = irq_get_chip(irq);
struct combiner_chip_data *chip_data = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned int irq = irq_desc_get_irq(desc);
unsigned int cascade_irq, combiner_irq;
unsigned long status;
@ -122,9 +123,8 @@ static struct irq_chip combiner_chip = {
static void __init combiner_cascade_irq(struct combiner_chip_data *combiner_data,
unsigned int irq)
{
if (irq_set_handler_data(irq, combiner_data) != 0)
BUG();
irq_set_chained_handler(irq, combiner_handle_cascade_irq);
irq_set_chained_handler_and_data(irq, combiner_handle_cascade_irq,
combiner_data);
}
static void __init combiner_init_one(struct combiner_chip_data *combiner_data,
@ -185,14 +185,14 @@ static void __init combiner_init(void __iomem *combiner_base,
combiner_data = kcalloc(max_nr, sizeof (*combiner_data), GFP_KERNEL);
if (!combiner_data) {
pr_warning("%s: could not allocate combiner data\n", __func__);
pr_warn("%s: could not allocate combiner data\n", __func__);
return;
}
combiner_irq_domain = irq_domain_add_linear(np, nr_irq,
&combiner_irq_domain_ops, combiner_data);
if (WARN_ON(!combiner_irq_domain)) {
pr_warning("%s: irq domain init failed\n", __func__);
pr_warn("%s: irq domain init failed\n", __func__);
return;
}

View File

@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/irqchip.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/cpu.h>
#include <linux/io.h>
@ -33,8 +34,6 @@
#include <asm/smp_plat.h>
#include <asm/mach/irq.h>
#include "irqchip.h"
/* Interrupt Controller Registers Map */
#define ARMADA_370_XP_INT_SET_MASK_OFFS (0x48)
#define ARMADA_370_XP_INT_CLEAR_MASK_OFFS (0x4C)
@ -451,7 +450,7 @@ static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {}
static void armada_370_xp_mpic_handle_cascade_irq(unsigned int irq,
struct irq_desc *desc)
{
struct irq_chip *chip = irq_get_chip(irq);
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned long irqmap, irqn, irqsrc, cpuid;
unsigned int cascade_irq;

View File

@ -19,6 +19,7 @@
#include <linux/bitmap.h>
#include <linux/types.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@ -31,7 +32,6 @@
#include <asm/mach/irq.h>
#include "irq-atmel-aic-common.h"
#include "irqchip.h"
/* Number of irq lines managed by AIC */
#define NR_AIC_IRQS 32
@ -225,7 +225,7 @@ static void __init at91sam9g45_aic_irq_fixup(struct device_node *root)
aic_common_rtt_irq_fixup(root);
}
static const struct of_device_id __initdata aic_irq_fixups[] = {
static const struct of_device_id aic_irq_fixups[] __initconst = {
{ .compatible = "atmel,at91rm9200", .data = at91rm9200_aic_irq_fixup },
{ .compatible = "atmel,at91sam9g45", .data = at91sam9g45_aic_irq_fixup },
{ .compatible = "atmel,at91sam9n12", .data = at91rm9200_aic_irq_fixup },

View File

@ -19,6 +19,7 @@
#include <linux/bitmap.h>
#include <linux/types.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@ -31,7 +32,6 @@
#include <asm/mach/irq.h>
#include "irq-atmel-aic-common.h"
#include "irqchip.h"
/* Number of irq lines managed by AIC */
#define NR_AIC5_IRQS 128
@ -290,7 +290,7 @@ static void __init sama5d3_aic_irq_fixup(struct device_node *root)
aic_common_rtc_irq_fixup(root);
}
static const struct of_device_id __initdata aic5_irq_fixups[] = {
static const struct of_device_id aic5_irq_fixups[] __initconst = {
{ .compatible = "atmel,sama5d3", .data = sama5d3_aic_irq_fixup },
{ .compatible = "atmel,sama5d4", .data = sama5d3_aic_irq_fixup },
{ /* sentinel */ },

View File

@ -48,13 +48,12 @@
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/irqchip.h>
#include <linux/irqdomain.h>
#include <asm/exception.h>
#include <asm/mach/irq.h>
#include "irqchip.h"
/* Put the bank and irq (32 bits) into the hwirq */
#define MAKE_HWIRQ(b, n) ((b << 5) | (n))
#define HWIRQ_BANK(i) (i >> 5)
@ -76,10 +75,10 @@
#define NR_BANKS 3
#define IRQS_PER_BANK 32
static int reg_pending[] __initconst = { 0x00, 0x04, 0x08 };
static int reg_enable[] __initconst = { 0x18, 0x10, 0x14 };
static int reg_disable[] __initconst = { 0x24, 0x1c, 0x20 };
static int bank_irqs[] __initconst = { 8, 32, 32 };
static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 };
static const int reg_enable[] __initconst = { 0x18, 0x10, 0x14 };
static const int reg_disable[] __initconst = { 0x24, 0x1c, 0x20 };
static const int bank_irqs[] __initconst = { 8, 32, 32 };
static const int shortcuts[] = {
7, 9, 10, 18, 19, /* Bank 1 */
@ -97,6 +96,7 @@ struct armctrl_ic {
static struct armctrl_ic intc __read_mostly;
static void __exception_irq_entry bcm2835_handle_irq(
struct pt_regs *regs);
static void bcm2836_chained_handle_irq(unsigned int irq, struct irq_desc *desc);
static void armctrl_mask_irq(struct irq_data *d)
{
@ -140,7 +140,8 @@ static const struct irq_domain_ops armctrl_ops = {
};
static int __init armctrl_of_init(struct device_node *node,
struct device_node *parent)
struct device_node *parent,
bool is_2836)
{
void __iomem *base;
int irq, b, i;
@ -169,54 +170,90 @@ static int __init armctrl_of_init(struct device_node *node,
}
}
set_handle_irq(bcm2835_handle_irq);
if (is_2836) {
int parent_irq = irq_of_parse_and_map(node, 0);
if (!parent_irq) {
panic("%s: unable to get parent interrupt.\n",
node->full_name);
}
irq_set_chained_handler(parent_irq, bcm2836_chained_handle_irq);
} else {
set_handle_irq(bcm2835_handle_irq);
}
return 0;
}
static int __init bcm2835_armctrl_of_init(struct device_node *node,
struct device_node *parent)
{
return armctrl_of_init(node, parent, false);
}
static int __init bcm2836_armctrl_of_init(struct device_node *node,
struct device_node *parent)
{
return armctrl_of_init(node, parent, true);
}
/*
* Handle each interrupt across the entire interrupt controller. This reads the
* status register before handling each interrupt, which is necessary given that
* handle_IRQ may briefly re-enable interrupts for soft IRQ handling.
*/
static void armctrl_handle_bank(int bank, struct pt_regs *regs)
static u32 armctrl_translate_bank(int bank)
{
u32 stat, irq;
u32 stat = readl_relaxed(intc.pending[bank]);
while ((stat = readl_relaxed(intc.pending[bank]))) {
irq = MAKE_HWIRQ(bank, ffs(stat) - 1);
handle_IRQ(irq_linear_revmap(intc.domain, irq), regs);
}
return MAKE_HWIRQ(bank, ffs(stat) - 1);
}
static void armctrl_handle_shortcut(int bank, struct pt_regs *regs,
u32 stat)
static u32 armctrl_translate_shortcut(int bank, u32 stat)
{
u32 irq = MAKE_HWIRQ(bank, shortcuts[ffs(stat >> SHORTCUT_SHIFT) - 1]);
handle_IRQ(irq_linear_revmap(intc.domain, irq), regs);
return MAKE_HWIRQ(bank, shortcuts[ffs(stat >> SHORTCUT_SHIFT) - 1]);
}
static u32 get_next_armctrl_hwirq(void)
{
u32 stat = readl_relaxed(intc.pending[0]) & BANK0_VALID_MASK;
if (stat == 0)
return ~0;
else if (stat & BANK0_HWIRQ_MASK)
return MAKE_HWIRQ(0, ffs(stat & BANK0_HWIRQ_MASK) - 1);
else if (stat & SHORTCUT1_MASK)
return armctrl_translate_shortcut(1, stat & SHORTCUT1_MASK);
else if (stat & SHORTCUT2_MASK)
return armctrl_translate_shortcut(2, stat & SHORTCUT2_MASK);
else if (stat & BANK1_HWIRQ)
return armctrl_translate_bank(1);
else if (stat & BANK2_HWIRQ)
return armctrl_translate_bank(2);
else
BUG();
}
static void __exception_irq_entry bcm2835_handle_irq(
struct pt_regs *regs)
{
u32 stat, irq;
u32 hwirq;
while ((stat = readl_relaxed(intc.pending[0]) & BANK0_VALID_MASK)) {
if (stat & BANK0_HWIRQ_MASK) {
irq = MAKE_HWIRQ(0, ffs(stat & BANK0_HWIRQ_MASK) - 1);
handle_IRQ(irq_linear_revmap(intc.domain, irq), regs);
} else if (stat & SHORTCUT1_MASK) {
armctrl_handle_shortcut(1, regs, stat & SHORTCUT1_MASK);
} else if (stat & SHORTCUT2_MASK) {
armctrl_handle_shortcut(2, regs, stat & SHORTCUT2_MASK);
} else if (stat & BANK1_HWIRQ) {
armctrl_handle_bank(1, regs);
} else if (stat & BANK2_HWIRQ) {
armctrl_handle_bank(2, regs);
} else {
BUG();
}
}
while ((hwirq = get_next_armctrl_hwirq()) != ~0)
handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs);
}
IRQCHIP_DECLARE(bcm2835_armctrl_ic, "brcm,bcm2835-armctrl-ic", armctrl_of_init);
static void bcm2836_chained_handle_irq(unsigned int irq, struct irq_desc *desc)
{
u32 hwirq;
while ((hwirq = get_next_armctrl_hwirq()) != ~0)
generic_handle_irq(irq_linear_revmap(intc.domain, hwirq));
}
IRQCHIP_DECLARE(bcm2835_armctrl_ic, "brcm,bcm2835-armctrl-ic",
bcm2835_armctrl_of_init);
IRQCHIP_DECLARE(bcm2836_armctrl_ic, "brcm,bcm2836-armctrl-ic",
bcm2836_armctrl_of_init);

View File

@ -0,0 +1,275 @@
/*
* Root interrupt controller for the BCM2836 (Raspberry Pi 2).
*
* Copyright 2015 Broadcom
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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.
*/
#include <linux/cpu.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/irqchip.h>
#include <linux/irqdomain.h>
#include <asm/exception.h>
/*
* The low 2 bits identify the CPU that the GPU IRQ goes to, and the
* next 2 bits identify the CPU that the GPU FIQ goes to.
*/
#define LOCAL_GPU_ROUTING 0x00c
/* When setting bits 0-3, enables PMU interrupts on that CPU. */
#define LOCAL_PM_ROUTING_SET 0x010
/* When setting bits 0-3, disables PMU interrupts on that CPU. */
#define LOCAL_PM_ROUTING_CLR 0x014
/*
* The low 4 bits of this are the CPU's timer IRQ enables, and the
* next 4 bits are the CPU's timer FIQ enables (which override the IRQ
* bits).
*/
#define LOCAL_TIMER_INT_CONTROL0 0x040
/*
* The low 4 bits of this are the CPU's per-mailbox IRQ enables, and
* the next 4 bits are the CPU's per-mailbox FIQ enables (which
* override the IRQ bits).
*/
#define LOCAL_MAILBOX_INT_CONTROL0 0x050
/*
* The CPU's interrupt status register. Bits are defined by the the
* LOCAL_IRQ_* bits below.
*/
#define LOCAL_IRQ_PENDING0 0x060
/* Same status bits as above, but for FIQ. */
#define LOCAL_FIQ_PENDING0 0x070
/*
* Mailbox0 write-to-set bits. There are 16 mailboxes, 4 per CPU, and
* these bits are organized by mailbox number and then CPU number. We
* use mailbox 0 for IPIs. The mailbox's interrupt is raised while
* any bit is set.
*/
#define LOCAL_MAILBOX0_SET0 0x080
/* Mailbox0 write-to-clear bits. */
#define LOCAL_MAILBOX0_CLR0 0x0c0
#define LOCAL_IRQ_CNTPSIRQ 0
#define LOCAL_IRQ_CNTPNSIRQ 1
#define LOCAL_IRQ_CNTHPIRQ 2
#define LOCAL_IRQ_CNTVIRQ 3
#define LOCAL_IRQ_MAILBOX0 4
#define LOCAL_IRQ_MAILBOX1 5
#define LOCAL_IRQ_MAILBOX2 6
#define LOCAL_IRQ_MAILBOX3 7
#define LOCAL_IRQ_GPU_FAST 8
#define LOCAL_IRQ_PMU_FAST 9
#define LAST_IRQ LOCAL_IRQ_PMU_FAST
struct bcm2836_arm_irqchip_intc {
struct irq_domain *domain;
void __iomem *base;
};
static struct bcm2836_arm_irqchip_intc intc __read_mostly;
static void bcm2836_arm_irqchip_mask_per_cpu_irq(unsigned int reg_offset,
unsigned int bit,
int cpu)
{
void __iomem *reg = intc.base + reg_offset + 4 * cpu;
writel(readl(reg) & ~BIT(bit), reg);
}
static void bcm2836_arm_irqchip_unmask_per_cpu_irq(unsigned int reg_offset,
unsigned int bit,
int cpu)
{
void __iomem *reg = intc.base + reg_offset + 4 * cpu;
writel(readl(reg) | BIT(bit), reg);
}
static void bcm2836_arm_irqchip_mask_timer_irq(struct irq_data *d)
{
bcm2836_arm_irqchip_mask_per_cpu_irq(LOCAL_TIMER_INT_CONTROL0,
d->hwirq - LOCAL_IRQ_CNTPSIRQ,
smp_processor_id());
}
static void bcm2836_arm_irqchip_unmask_timer_irq(struct irq_data *d)
{
bcm2836_arm_irqchip_unmask_per_cpu_irq(LOCAL_TIMER_INT_CONTROL0,
d->hwirq - LOCAL_IRQ_CNTPSIRQ,
smp_processor_id());
}
static struct irq_chip bcm2836_arm_irqchip_timer = {
.name = "bcm2836-timer",
.irq_mask = bcm2836_arm_irqchip_mask_timer_irq,
.irq_unmask = bcm2836_arm_irqchip_unmask_timer_irq,
};
static void bcm2836_arm_irqchip_mask_pmu_irq(struct irq_data *d)
{
writel(1 << smp_processor_id(), intc.base + LOCAL_PM_ROUTING_CLR);
}
static void bcm2836_arm_irqchip_unmask_pmu_irq(struct irq_data *d)
{
writel(1 << smp_processor_id(), intc.base + LOCAL_PM_ROUTING_SET);
}
static struct irq_chip bcm2836_arm_irqchip_pmu = {
.name = "bcm2836-pmu",
.irq_mask = bcm2836_arm_irqchip_mask_pmu_irq,
.irq_unmask = bcm2836_arm_irqchip_unmask_pmu_irq,
};
static void bcm2836_arm_irqchip_mask_gpu_irq(struct irq_data *d)
{
}
static void bcm2836_arm_irqchip_unmask_gpu_irq(struct irq_data *d)
{
}
static struct irq_chip bcm2836_arm_irqchip_gpu = {
.name = "bcm2836-gpu",
.irq_mask = bcm2836_arm_irqchip_mask_gpu_irq,
.irq_unmask = bcm2836_arm_irqchip_unmask_gpu_irq,
};
static void bcm2836_arm_irqchip_register_irq(int hwirq, struct irq_chip *chip)
{
int irq = irq_create_mapping(intc.domain, hwirq);
irq_set_percpu_devid(irq);
irq_set_chip_and_handler(irq, chip, handle_percpu_devid_irq);
irq_set_status_flags(irq, IRQ_NOAUTOEN);
}
static void
__exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs)
{
int cpu = smp_processor_id();
u32 stat;
stat = readl_relaxed(intc.base + LOCAL_IRQ_PENDING0 + 4 * cpu);
if (stat & 0x10) {
#ifdef CONFIG_SMP
void __iomem *mailbox0 = (intc.base +
LOCAL_MAILBOX0_CLR0 + 16 * cpu);
u32 mbox_val = readl(mailbox0);
u32 ipi = ffs(mbox_val) - 1;
writel(1 << ipi, mailbox0);
handle_IPI(ipi, regs);
#endif
} else {
u32 hwirq = ffs(stat) - 1;
handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs);
}
}
#ifdef CONFIG_SMP
static void bcm2836_arm_irqchip_send_ipi(const struct cpumask *mask,
unsigned int ipi)
{
int cpu;
void __iomem *mailbox0_base = intc.base + LOCAL_MAILBOX0_SET0;
/*
* Ensure that stores to normal memory are visible to the
* other CPUs before issuing the IPI.
*/
dsb();
for_each_cpu(cpu, mask) {
writel(1 << ipi, mailbox0_base + 16 * cpu);
}
}
/* Unmasks the IPI on the CPU when it's online. */
static int bcm2836_arm_irqchip_cpu_notify(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
unsigned int int_reg = LOCAL_MAILBOX_INT_CONTROL0;
unsigned int mailbox = 0;
if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
bcm2836_arm_irqchip_unmask_per_cpu_irq(int_reg, mailbox, cpu);
else if (action == CPU_DYING)
bcm2836_arm_irqchip_mask_per_cpu_irq(int_reg, mailbox, cpu);
return NOTIFY_OK;
}
static struct notifier_block bcm2836_arm_irqchip_cpu_notifier = {
.notifier_call = bcm2836_arm_irqchip_cpu_notify,
.priority = 100,
};
#endif
static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = {
.xlate = irq_domain_xlate_onecell
};
static void
bcm2836_arm_irqchip_smp_init(void)
{
#ifdef CONFIG_SMP
/* Unmask IPIs to the boot CPU. */
bcm2836_arm_irqchip_cpu_notify(&bcm2836_arm_irqchip_cpu_notifier,
CPU_STARTING,
(void *)smp_processor_id());
register_cpu_notifier(&bcm2836_arm_irqchip_cpu_notifier);
set_smp_cross_call(bcm2836_arm_irqchip_send_ipi);
#endif
}
static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node,
struct device_node *parent)
{
intc.base = of_iomap(node, 0);
if (!intc.base) {
panic("%s: unable to map local interrupt registers\n",
node->full_name);
}
intc.domain = irq_domain_add_linear(node, LAST_IRQ + 1,
&bcm2836_arm_irqchip_intc_ops,
NULL);
if (!intc.domain)
panic("%s: unable to create IRQ domain\n", node->full_name);
bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTPSIRQ,
&bcm2836_arm_irqchip_timer);
bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTPNSIRQ,
&bcm2836_arm_irqchip_timer);
bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTHPIRQ,
&bcm2836_arm_irqchip_timer);
bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTVIRQ,
&bcm2836_arm_irqchip_timer);
bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_GPU_FAST,
&bcm2836_arm_irqchip_gpu);
bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_PMU_FAST,
&bcm2836_arm_irqchip_pmu);
bcm2836_arm_irqchip_smp_init();
set_handle_irq(bcm2836_arm_irqchip_handle_irq);
return 0;
}
IRQCHIP_DECLARE(bcm2836_arm_irqchip_l1_intc, "brcm,bcm2836-l1-intc",
bcm2836_arm_irqchip_l1_intc_of_init);

View File

@ -29,10 +29,9 @@
#include <linux/slab.h>
#include <linux/smp.h>
#include <linux/types.h>
#include <linux/irqchip.h>
#include <linux/irqchip/chained_irq.h>
#include "irqchip.h"
#define IRQS_PER_WORD 32
#define REG_BYTES_PER_IRQ_WORD (sizeof(u32) * 4)
#define MAX_WORDS 8
@ -257,8 +256,8 @@ static int __init bcm7038_l1_init_one(struct device_node *dn,
pr_err("failed to map parent interrupt %d\n", parent_irq);
return -EINVAL;
}
irq_set_handler_data(parent_irq, intc);
irq_set_chained_handler(parent_irq, bcm7038_l1_irq_handle);
irq_set_chained_handler_and_data(parent_irq, bcm7038_l1_irq_handle,
intc);
return 0;
}

View File

@ -26,10 +26,9 @@
#include <linux/irqdomain.h>
#include <linux/reboot.h>
#include <linux/bitops.h>
#include <linux/irqchip.h>
#include <linux/irqchip/chained_irq.h>
#include "irqchip.h"
/* Register offset in the L2 interrupt controller */
#define IRQEN 0x00
#define IRQSTAT 0x04
@ -38,6 +37,11 @@
#define MAX_MAPPINGS (MAX_WORDS * 2)
#define IRQS_PER_WORD 32
struct bcm7120_l1_intc_data {
struct bcm7120_l2_intc_data *b;
u32 irq_map_mask[MAX_WORDS];
};
struct bcm7120_l2_intc_data {
unsigned int n_words;
void __iomem *map_base[MAX_MAPPINGS];
@ -47,14 +51,15 @@ struct bcm7120_l2_intc_data {
struct irq_domain *domain;
bool can_wake;
u32 irq_fwd_mask[MAX_WORDS];
u32 irq_map_mask[MAX_WORDS];
struct bcm7120_l1_intc_data *l1_data;
int num_parent_irqs;
const __be32 *map_mask_prop;
};
static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
{
struct bcm7120_l2_intc_data *b = irq_desc_get_handler_data(desc);
struct bcm7120_l1_intc_data *data = irq_desc_get_handler_data(desc);
struct bcm7120_l2_intc_data *b = data->b;
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned int idx;
@ -69,7 +74,8 @@ static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
irq_gc_lock(gc);
pending = irq_reg_readl(gc, b->stat_offset[idx]) &
gc->mask_cache;
gc->mask_cache &
data->irq_map_mask[idx];
irq_gc_unlock(gc);
for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) {
@ -81,11 +87,10 @@ static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
static void bcm7120_l2_intc_suspend(struct irq_data *d)
static void bcm7120_l2_intc_suspend(struct irq_chip_generic *gc)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct irq_chip_type *ct = irq_data_get_chip_type(d);
struct bcm7120_l2_intc_data *b = gc->private;
struct irq_chip_type *ct = gc->chip_types;
irq_gc_lock(gc);
if (b->can_wake)
@ -94,10 +99,9 @@ static void bcm7120_l2_intc_suspend(struct irq_data *d)
irq_gc_unlock(gc);
}
static void bcm7120_l2_intc_resume(struct irq_data *d)
static void bcm7120_l2_intc_resume(struct irq_chip_generic *gc)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct irq_chip_type *ct = irq_data_get_chip_type(d);
struct irq_chip_type *ct = gc->chip_types;
/* Restore the saved mask */
irq_gc_lock(gc);
@ -107,8 +111,9 @@ static void bcm7120_l2_intc_resume(struct irq_data *d)
static int bcm7120_l2_intc_init_one(struct device_node *dn,
struct bcm7120_l2_intc_data *data,
int irq)
int irq, u32 *valid_mask)
{
struct bcm7120_l1_intc_data *l1_data = &data->l1_data[irq];
int parent_irq;
unsigned int idx;
@ -120,20 +125,28 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn,
/* For multiple parent IRQs with multiple words, this looks like:
* <irq0_w0 irq0_w1 irq1_w0 irq1_w1 ...>
*
* We need to associate a given parent interrupt with its corresponding
* map_mask in order to mask the status register with it because we
* have the same handler being called for multiple parent interrupts.
*
* This is typically something needed on BCM7xxx (STB chips).
*/
for (idx = 0; idx < data->n_words; idx++) {
if (data->map_mask_prop) {
data->irq_map_mask[idx] |=
l1_data->irq_map_mask[idx] |=
be32_to_cpup(data->map_mask_prop +
irq * data->n_words + idx);
} else {
data->irq_map_mask[idx] = 0xffffffff;
l1_data->irq_map_mask[idx] = 0xffffffff;
}
valid_mask[idx] |= l1_data->irq_map_mask[idx];
}
irq_set_handler_data(parent_irq, data);
irq_set_chained_handler(parent_irq, bcm7120_l2_intc_irq_handle);
l1_data->b = data;
irq_set_chained_handler_and_data(parent_irq,
bcm7120_l2_intc_irq_handle, l1_data);
return 0;
}
@ -214,6 +227,7 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn,
struct irq_chip_type *ct;
int ret = 0;
unsigned int idx, irq, flags;
u32 valid_mask[MAX_WORDS] = { };
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
@ -226,9 +240,16 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn,
goto out_unmap;
}
data->l1_data = kcalloc(data->num_parent_irqs, sizeof(*data->l1_data),
GFP_KERNEL);
if (!data->l1_data) {
ret = -ENOMEM;
goto out_free_l1_data;
}
ret = iomap_regs_fn(dn, data);
if (ret < 0)
goto out_unmap;
goto out_free_l1_data;
for (idx = 0; idx < data->n_words; idx++) {
__raw_writel(data->irq_fwd_mask[idx],
@ -237,16 +258,16 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn,
}
for (irq = 0; irq < data->num_parent_irqs; irq++) {
ret = bcm7120_l2_intc_init_one(dn, data, irq);
ret = bcm7120_l2_intc_init_one(dn, data, irq, valid_mask);
if (ret)
goto out_unmap;
goto out_free_l1_data;
}
data->domain = irq_domain_add_linear(dn, IRQS_PER_WORD * data->n_words,
&irq_generic_chip_ops, NULL);
if (!data->domain) {
ret = -ENOMEM;
goto out_unmap;
goto out_free_l1_data;
}
/* MIPS chips strapped for BE will automagically configure the
@ -270,7 +291,7 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn,
irq = idx * IRQS_PER_WORD;
gc = irq_get_domain_generic_chip(data->domain, irq);
gc->unused = 0xffffffff & ~data->irq_map_mask[idx];
gc->unused = 0xffffffff & ~valid_mask[idx];
gc->private = data;
ct = gc->chip_types;
@ -280,8 +301,15 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn,
ct->chip.irq_mask = irq_gc_mask_clr_bit;
ct->chip.irq_unmask = irq_gc_mask_set_bit;
ct->chip.irq_ack = irq_gc_noop;
ct->chip.irq_suspend = bcm7120_l2_intc_suspend;
ct->chip.irq_resume = bcm7120_l2_intc_resume;
gc->suspend = bcm7120_l2_intc_suspend;
gc->resume = bcm7120_l2_intc_resume;
/*
* Initialize mask-cache, in case we need it for
* saving/restoring fwd mask even w/o any child interrupts
* installed
*/
gc->mask_cache = irq_reg_readl(gc, ct->regs.mask);
if (data->can_wake) {
/* This IRQ chip can wake the system, set all
@ -300,6 +328,8 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn,
out_free_domain:
irq_domain_remove(data->domain);
out_free_l1_data:
kfree(data->l1_data);
out_unmap:
for (idx = 0; idx < MAX_MAPPINGS; idx++) {
if (data->map_base[idx])

View File

@ -32,8 +32,6 @@
#include <linux/irqchip.h>
#include <linux/irqchip/chained_irq.h>
#include "irqchip.h"
/* Register offsets in the L2 interrupt controller */
#define CPU_STATUS 0x00
#define CPU_SET 0x04
@ -51,11 +49,13 @@ struct brcmstb_l2_intc_data {
u32 saved_mask; /* for suspend/resume */
};
static void brcmstb_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
static void brcmstb_l2_intc_irq_handle(unsigned int __irq,
struct irq_desc *desc)
{
struct brcmstb_l2_intc_data *b = irq_desc_get_handler_data(desc);
struct irq_chip_generic *gc = irq_get_domain_generic_chip(b->domain, 0);
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned int irq = irq_desc_get_irq(desc);
u32 status;
chained_irq_enter(chip, desc);
@ -172,8 +172,8 @@ int __init brcmstb_l2_intc_of_init(struct device_node *np,
}
/* Set the IRQ chaining logic */
irq_set_handler_data(data->parent_irq, data);
irq_set_chained_handler(data->parent_irq, brcmstb_l2_intc_irq_handle);
irq_set_chained_handler_and_data(data->parent_irq,
brcmstb_l2_intc_irq_handle, data);
gc = irq_get_domain_generic_chip(data->domain, 0);
gc->reg_base = data->base;

View File

@ -11,6 +11,7 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/irqdomain.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@ -19,8 +20,6 @@
#include <asm/exception.h>
#include <asm/mach/irq.h>
#include "irqchip.h"
#define CLPS711X_INTSR1 (0x0240)
#define CLPS711X_INTMR1 (0x0280)
#define CLPS711X_BLEOI (0x0600)

View File

@ -11,13 +11,12 @@
*/
#include <linux/err.h>
#include <linux/io.h>
#include <linux/irqchip.h>
#include <linux/irqdomain.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#include "irqchip.h"
#define IRQ_FREE -1
#define IRQ_RESERVED -2
#define IRQ_SKIP -3

View File

@ -12,6 +12,7 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@ -20,8 +21,6 @@
#include <asm/exception.h>
#include "irqchip.h"
#define UC_IRQ_CONTROL 0x04
#define IC_FLAG_CLEAR_LO 0x00

View File

@ -13,36 +13,36 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include "irqchip.h"
#define APB_INT_ENABLE_L 0x00
#define APB_INT_ENABLE_H 0x04
#define APB_INT_MASK_L 0x08
#define APB_INT_MASK_H 0x0c
#define APB_INT_FINALSTATUS_L 0x30
#define APB_INT_FINALSTATUS_H 0x34
#define APB_INT_BASE_OFFSET 0x04
static void dw_apb_ictl_handler(unsigned int irq, struct irq_desc *desc)
{
struct irq_chip *chip = irq_get_chip(irq);
struct irq_chip_generic *gc = irq_get_handler_data(irq);
struct irq_domain *d = gc->private;
u32 stat;
struct irq_domain *d = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
int n;
chained_irq_enter(chip, desc);
for (n = 0; n < gc->num_ct; n++) {
stat = readl_relaxed(gc->reg_base +
APB_INT_FINALSTATUS_L + 4 * n);
for (n = 0; n < d->revmap_size; n += 32) {
struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, n);
u32 stat = readl_relaxed(gc->reg_base + APB_INT_FINALSTATUS_L);
while (stat) {
u32 hwirq = ffs(stat) - 1;
generic_handle_irq(irq_find_mapping(d,
gc->irq_base + hwirq + 32 * n));
u32 virq = irq_find_mapping(d, gc->irq_base + hwirq);
generic_handle_irq(virq);
stat &= ~(1 << hwirq);
}
}
@ -73,7 +73,7 @@ static int __init dw_apb_ictl_init(struct device_node *np,
struct irq_domain *domain;
struct irq_chip_generic *gc;
void __iomem *iobase;
int ret, nrirqs, irq;
int ret, nrirqs, irq, i;
u32 reg;
/* Map the parent interrupt for the chained handler */
@ -128,35 +128,25 @@ static int __init dw_apb_ictl_init(struct device_node *np,
goto err_unmap;
}
ret = irq_alloc_domain_generic_chips(domain, 32, (nrirqs > 32) ? 2 : 1,
np->name, handle_level_irq, clr, 0,
IRQ_GC_MASK_CACHE_PER_TYPE |
ret = irq_alloc_domain_generic_chips(domain, 32, 1, np->name,
handle_level_irq, clr, 0,
IRQ_GC_INIT_MASK_CACHE);
if (ret) {
pr_err("%s: unable to alloc irq domain gc\n", np->full_name);
goto err_unmap;
}
gc = irq_get_domain_generic_chip(domain, 0);
gc->private = domain;
gc->reg_base = iobase;
gc->chip_types[0].regs.mask = APB_INT_MASK_L;
gc->chip_types[0].regs.enable = APB_INT_ENABLE_L;
gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit;
gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit;
gc->chip_types[0].chip.irq_resume = dw_apb_ictl_resume;
if (nrirqs > 32) {
gc->chip_types[1].regs.mask = APB_INT_MASK_H;
gc->chip_types[1].regs.enable = APB_INT_ENABLE_H;
gc->chip_types[1].chip.irq_mask = irq_gc_mask_set_bit;
gc->chip_types[1].chip.irq_unmask = irq_gc_mask_clr_bit;
gc->chip_types[1].chip.irq_resume = dw_apb_ictl_resume;
for (i = 0; i < DIV_ROUND_UP(nrirqs, 32); i++) {
gc = irq_get_domain_generic_chip(domain, i * 32);
gc->reg_base = iobase + i * APB_INT_BASE_OFFSET;
gc->chip_types[0].regs.mask = APB_INT_MASK_L;
gc->chip_types[0].regs.enable = APB_INT_ENABLE_L;
gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit;
gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit;
gc->chip_types[0].chip.irq_resume = dw_apb_ictl_resume;
}
irq_set_handler_data(irq, gc);
irq_set_chained_handler(irq, dw_apb_ictl_handler);
irq_set_chained_handler_and_data(irq, dw_apb_ictl_handler, domain);
return 0;

View File

@ -45,13 +45,11 @@
struct v2m_data {
spinlock_t msi_cnt_lock;
struct msi_controller mchip;
struct resource res; /* GICv2m resource */
void __iomem *base; /* GICv2m virt address */
u32 spi_start; /* The SPI number that MSIs start */
u32 nr_spis; /* The number of SPIs for MSIs */
unsigned long *bm; /* MSI vector bitmap */
struct irq_domain *domain;
};
static void gicv2m_mask_msi_irq(struct irq_data *d)
@ -213,11 +211,25 @@ static bool is_msi_spi_valid(u32 base, u32 num)
return true;
}
static struct irq_chip gicv2m_pmsi_irq_chip = {
.name = "pMSI",
};
static struct msi_domain_ops gicv2m_pmsi_ops = {
};
static struct msi_domain_info gicv2m_pmsi_domain_info = {
.flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
.ops = &gicv2m_pmsi_ops,
.chip = &gicv2m_pmsi_irq_chip,
};
static int __init gicv2m_init_one(struct device_node *node,
struct irq_domain *parent)
{
int ret;
struct v2m_data *v2m;
struct irq_domain *inner_domain, *pci_domain, *plat_domain;
v2m = kzalloc(sizeof(struct v2m_data), GFP_KERNEL);
if (!v2m) {
@ -261,32 +273,28 @@ static int __init gicv2m_init_one(struct device_node *node,
goto err_iounmap;
}
v2m->domain = irq_domain_add_tree(NULL, &gicv2m_domain_ops, v2m);
if (!v2m->domain) {
inner_domain = irq_domain_add_tree(node, &gicv2m_domain_ops, v2m);
if (!inner_domain) {
pr_err("Failed to create GICv2m domain\n");
ret = -ENOMEM;
goto err_free_bm;
}
v2m->domain->parent = parent;
v2m->mchip.of_node = node;
v2m->mchip.domain = pci_msi_create_irq_domain(node,
&gicv2m_msi_domain_info,
v2m->domain);
if (!v2m->mchip.domain) {
pr_err("Failed to create MSI domain\n");
inner_domain->bus_token = DOMAIN_BUS_NEXUS;
inner_domain->parent = parent;
pci_domain = pci_msi_create_irq_domain(node, &gicv2m_msi_domain_info,
inner_domain);
plat_domain = platform_msi_create_irq_domain(node,
&gicv2m_pmsi_domain_info,
inner_domain);
if (!pci_domain || !plat_domain) {
pr_err("Failed to create MSI domains\n");
ret = -ENOMEM;
goto err_free_domains;
}
spin_lock_init(&v2m->msi_cnt_lock);
ret = of_pci_msi_chip_add(&v2m->mchip);
if (ret) {
pr_err("Failed to add msi_chip.\n");
goto err_free_domains;
}
pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", node->name,
(unsigned long)v2m->res.start, (unsigned long)v2m->res.end,
v2m->spi_start, (v2m->spi_start + v2m->nr_spis));
@ -294,10 +302,12 @@ static int __init gicv2m_init_one(struct device_node *node,
return 0;
err_free_domains:
if (v2m->mchip.domain)
irq_domain_remove(v2m->mchip.domain);
if (v2m->domain)
irq_domain_remove(v2m->domain);
if (plat_domain)
irq_domain_remove(plat_domain);
if (pci_domain)
irq_domain_remove(pci_domain);
if (inner_domain)
irq_domain_remove(inner_domain);
err_free_bm:
kfree(v2m->bm);
err_iounmap:

View File

@ -0,0 +1,140 @@
/*
* Copyright (C) 2013-2015 ARM Limited, All Rights Reserved.
* Author: Marc Zyngier <marc.zyngier@arm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/msi.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_pci.h>
static void its_mask_msi_irq(struct irq_data *d)
{
pci_msi_mask_irq(d);
irq_chip_mask_parent(d);
}
static void its_unmask_msi_irq(struct irq_data *d)
{
pci_msi_unmask_irq(d);
irq_chip_unmask_parent(d);
}
static struct irq_chip its_msi_irq_chip = {
.name = "ITS-MSI",
.irq_unmask = its_unmask_msi_irq,
.irq_mask = its_mask_msi_irq,
.irq_eoi = irq_chip_eoi_parent,
.irq_write_msi_msg = pci_msi_domain_write_msg,
};
struct its_pci_alias {
struct pci_dev *pdev;
u32 dev_id;
u32 count;
};
static int its_pci_msi_vec_count(struct pci_dev *pdev)
{
int msi, msix;
msi = max(pci_msi_vec_count(pdev), 0);
msix = max(pci_msix_vec_count(pdev), 0);
return max(msi, msix);
}
static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data)
{
struct its_pci_alias *dev_alias = data;
dev_alias->dev_id = alias;
if (pdev != dev_alias->pdev)
dev_alias->count += its_pci_msi_vec_count(dev_alias->pdev);
return 0;
}
static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
int nvec, msi_alloc_info_t *info)
{
struct pci_dev *pdev;
struct its_pci_alias dev_alias;
struct msi_domain_info *msi_info;
if (!dev_is_pci(dev))
return -EINVAL;
msi_info = msi_get_domain_info(domain->parent);
pdev = to_pci_dev(dev);
dev_alias.pdev = pdev;
dev_alias.count = nvec;
pci_for_each_dma_alias(pdev, its_get_pci_alias, &dev_alias);
/* ITS specific DeviceID, as the core ITS ignores dev. */
info->scratchpad[0].ul = dev_alias.dev_id;
return msi_info->ops->msi_prepare(domain->parent,
dev, dev_alias.count, info);
}
static struct msi_domain_ops its_pci_msi_ops = {
.msi_prepare = its_pci_msi_prepare,
};
static struct msi_domain_info its_pci_msi_domain_info = {
.flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX),
.ops = &its_pci_msi_ops,
.chip = &its_msi_irq_chip,
};
static struct of_device_id its_device_id[] = {
{ .compatible = "arm,gic-v3-its", },
{},
};
static int __init its_pci_msi_init(void)
{
struct device_node *np;
struct irq_domain *parent;
for (np = of_find_matching_node(NULL, its_device_id); np;
np = of_find_matching_node(np, its_device_id)) {
if (!of_property_read_bool(np, "msi-controller"))
continue;
parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS);
if (!parent || !msi_get_domain_info(parent)) {
pr_err("%s: unable to locate ITS domain\n",
np->full_name);
continue;
}
if (!pci_msi_create_irq_domain(np, &its_pci_msi_domain_info,
parent)) {
pr_err("%s: unable to create PCI domain\n",
np->full_name);
continue;
}
pr_info("PCI/MSI: %s domain created\n", np->full_name);
}
return 0;
}
early_initcall(its_pci_msi_init);

View File

@ -0,0 +1,93 @@
/*
* Copyright (C) 2013-2015 ARM Limited, All Rights Reserved.
* Author: Marc Zyngier <marc.zyngier@arm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/device.h>
#include <linux/msi.h>
#include <linux/of.h>
#include <linux/of_irq.h>
static struct irq_chip its_pmsi_irq_chip = {
.name = "ITS-pMSI",
};
static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
int nvec, msi_alloc_info_t *info)
{
struct msi_domain_info *msi_info;
u32 dev_id;
int ret;
msi_info = msi_get_domain_info(domain->parent);
/* Suck the DeviceID out of the msi-parent property */
ret = of_property_read_u32_index(dev->of_node, "msi-parent",
1, &dev_id);
if (ret)
return ret;
/* ITS specific DeviceID, as the core ITS ignores dev. */
info->scratchpad[0].ul = dev_id;
return msi_info->ops->msi_prepare(domain->parent,
dev, nvec, info);
}
static struct msi_domain_ops its_pmsi_ops = {
.msi_prepare = its_pmsi_prepare,
};
static struct msi_domain_info its_pmsi_domain_info = {
.flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
.ops = &its_pmsi_ops,
.chip = &its_pmsi_irq_chip,
};
static struct of_device_id its_device_id[] = {
{ .compatible = "arm,gic-v3-its", },
{},
};
static int __init its_pmsi_init(void)
{
struct device_node *np;
struct irq_domain *parent;
for (np = of_find_matching_node(NULL, its_device_id); np;
np = of_find_matching_node(np, its_device_id)) {
if (!of_property_read_bool(np, "msi-controller"))
continue;
parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS);
if (!parent || !msi_get_domain_info(parent)) {
pr_err("%s: unable to locate ITS domain\n",
np->full_name);
continue;
}
if (!platform_msi_create_irq_domain(np, &its_pmsi_domain_info,
parent)) {
pr_err("%s: unable to create platform domain\n",
np->full_name);
continue;
}
pr_info("Platform MSI: %s domain created\n", np->full_name);
}
return 0;
}
early_initcall(its_pmsi_init);

View File

@ -30,14 +30,13 @@
#include <linux/percpu.h>
#include <linux/slab.h>
#include <linux/irqchip.h>
#include <linux/irqchip/arm-gic-v3.h>
#include <asm/cacheflush.h>
#include <asm/cputype.h>
#include <asm/exception.h>
#include "irqchip.h"
#define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1 << 0)
#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0)
@ -54,14 +53,12 @@ struct its_collection {
/*
* The ITS structure - contains most of the infrastructure, with the
* msi_controller, the command queue, the collections, and the list of
* devices writing to it.
* top-level MSI domain, the command queue, the collections, and the
* list of devices writing to it.
*/
struct its_node {
raw_spinlock_t lock;
struct list_head entry;
struct msi_controller msi_chip;
struct irq_domain *domain;
void __iomem *base;
unsigned long phys_base;
struct its_cmd_block *cmd_base;
@ -643,26 +640,6 @@ static struct irq_chip its_irq_chip = {
.irq_compose_msi_msg = its_irq_compose_msi_msg,
};
static void its_mask_msi_irq(struct irq_data *d)
{
pci_msi_mask_irq(d);
irq_chip_mask_parent(d);
}
static void its_unmask_msi_irq(struct irq_data *d)
{
pci_msi_unmask_irq(d);
irq_chip_unmask_parent(d);
}
static struct irq_chip its_msi_irq_chip = {
.name = "ITS-MSI",
.irq_unmask = its_unmask_msi_irq,
.irq_mask = its_mask_msi_irq,
.irq_eoi = irq_chip_eoi_parent,
.irq_write_msi_msg = pci_msi_domain_write_msg,
};
/*
* How we allocate LPIs:
*
@ -831,7 +808,7 @@ static void its_free_tables(struct its_node *its)
}
}
static int its_alloc_tables(struct its_node *its)
static int its_alloc_tables(const char *node_name, struct its_node *its)
{
int err;
int i;
@ -874,7 +851,7 @@ static int its_alloc_tables(struct its_node *its)
if (order >= MAX_ORDER) {
order = MAX_ORDER - 1;
pr_warn("%s: Device Table too large, reduce its page order to %u\n",
its->msi_chip.of_node->full_name, order);
node_name, order);
}
}
@ -944,7 +921,7 @@ retry_baser:
if (val != tmp) {
pr_err("ITS: %s: GITS_BASER%d doesn't stick: %lx %lx\n",
its->msi_chip.of_node->full_name, i,
node_name, i,
(unsigned long) val, (unsigned long) tmp);
err = -ENXIO;
goto out_free;
@ -1209,85 +1186,50 @@ static int its_alloc_device_irq(struct its_device *dev, irq_hw_number_t *hwirq)
return 0;
}
struct its_pci_alias {
struct pci_dev *pdev;
u32 dev_id;
u32 count;
};
static int its_pci_msi_vec_count(struct pci_dev *pdev)
{
int msi, msix;
msi = max(pci_msi_vec_count(pdev), 0);
msix = max(pci_msix_vec_count(pdev), 0);
return max(msi, msix);
}
static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data)
{
struct its_pci_alias *dev_alias = data;
dev_alias->dev_id = alias;
if (pdev != dev_alias->pdev)
dev_alias->count += its_pci_msi_vec_count(dev_alias->pdev);
return 0;
}
static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
int nvec, msi_alloc_info_t *info)
{
struct pci_dev *pdev;
struct its_node *its;
struct its_device *its_dev;
struct its_pci_alias dev_alias;
struct msi_domain_info *msi_info;
u32 dev_id;
if (!dev_is_pci(dev))
return -EINVAL;
/*
* We ignore "dev" entierely, and rely on the dev_id that has
* been passed via the scratchpad. This limits this domain's
* usefulness to upper layers that definitely know that they
* are built on top of the ITS.
*/
dev_id = info->scratchpad[0].ul;
pdev = to_pci_dev(dev);
dev_alias.pdev = pdev;
dev_alias.count = nvec;
msi_info = msi_get_domain_info(domain);
its = msi_info->data;
pci_for_each_dma_alias(pdev, its_get_pci_alias, &dev_alias);
its = domain->parent->host_data;
its_dev = its_find_device(its, dev_alias.dev_id);
its_dev = its_find_device(its, dev_id);
if (its_dev) {
/*
* We already have seen this ID, probably through
* another alias (PCI bridge of some sort). No need to
* create the device.
*/
dev_dbg(dev, "Reusing ITT for devID %x\n", dev_alias.dev_id);
pr_debug("Reusing ITT for devID %x\n", dev_id);
goto out;
}
its_dev = its_create_device(its, dev_alias.dev_id, dev_alias.count);
its_dev = its_create_device(its, dev_id, nvec);
if (!its_dev)
return -ENOMEM;
dev_dbg(&pdev->dev, "ITT %d entries, %d bits\n",
dev_alias.count, ilog2(dev_alias.count));
pr_debug("ITT %d entries, %d bits\n", nvec, ilog2(nvec));
out:
info->scratchpad[0].ptr = its_dev;
info->scratchpad[1].ptr = dev;
return 0;
}
static struct msi_domain_ops its_pci_msi_ops = {
static struct msi_domain_ops its_msi_domain_ops = {
.msi_prepare = its_msi_prepare,
};
static struct msi_domain_info its_pci_msi_domain_info = {
.flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX),
.ops = &its_pci_msi_ops,
.chip = &its_msi_irq_chip,
};
static int its_irq_gic_domain_alloc(struct irq_domain *domain,
unsigned int virq,
irq_hw_number_t hwirq)
@ -1323,9 +1265,9 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
irq_domain_set_hwirq_and_chip(domain, virq + i,
hwirq, &its_irq_chip, its_dev);
dev_dbg(info->scratchpad[1].ptr, "ID:%d pID:%d vID:%d\n",
(int)(hwirq - its_dev->event_map.lpi_base),
(int)hwirq, virq + i);
pr_debug("ID:%d pID:%d vID:%d\n",
(int)(hwirq - its_dev->event_map.lpi_base),
(int) hwirq, virq + i);
}
return 0;
@ -1426,6 +1368,7 @@ static int its_probe(struct device_node *node, struct irq_domain *parent)
struct resource res;
struct its_node *its;
void __iomem *its_base;
struct irq_domain *inner_domain;
u32 val;
u64 baser, tmp;
int err;
@ -1469,7 +1412,6 @@ static int its_probe(struct device_node *node, struct irq_domain *parent)
INIT_LIST_HEAD(&its->its_device_list);
its->base = its_base;
its->phys_base = res.start;
its->msi_chip.of_node = node;
its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1;
its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL);
@ -1479,7 +1421,7 @@ static int its_probe(struct device_node *node, struct irq_domain *parent)
}
its->cmd_write = its->cmd_base;
err = its_alloc_tables(its);
err = its_alloc_tables(node->full_name, its);
if (err)
goto out_free_cmd;
@ -1515,26 +1457,27 @@ static int its_probe(struct device_node *node, struct irq_domain *parent)
writeq_relaxed(0, its->base + GITS_CWRITER);
writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR);
if (of_property_read_bool(its->msi_chip.of_node, "msi-controller")) {
its->domain = irq_domain_add_tree(NULL, &its_domain_ops, its);
if (!its->domain) {
if (of_property_read_bool(node, "msi-controller")) {
struct msi_domain_info *info;
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
err = -ENOMEM;
goto out_free_tables;
}
its->domain->parent = parent;
its->msi_chip.domain = pci_msi_create_irq_domain(node,
&its_pci_msi_domain_info,
its->domain);
if (!its->msi_chip.domain) {
inner_domain = irq_domain_add_tree(node, &its_domain_ops, its);
if (!inner_domain) {
err = -ENOMEM;
goto out_free_domains;
kfree(info);
goto out_free_tables;
}
err = of_pci_msi_chip_add(&its->msi_chip);
if (err)
goto out_free_domains;
inner_domain->parent = parent;
inner_domain->bus_token = DOMAIN_BUS_NEXUS;
info->ops = &its_msi_domain_ops;
info->data = its;
inner_domain->host_data = info;
}
spin_lock(&its_lock);
@ -1543,11 +1486,6 @@ static int its_probe(struct device_node *node, struct irq_domain *parent)
return 0;
out_free_domains:
if (its->msi_chip.domain)
irq_domain_remove(its->msi_chip.domain);
if (its->domain)
irq_domain_remove(its->domain);
out_free_tables:
its_free_tables(its);
out_free_cmd:

View File

@ -25,6 +25,7 @@
#include <linux/percpu.h>
#include <linux/slab.h>
#include <linux/irqchip.h>
#include <linux/irqchip/arm-gic-v3.h>
#include <asm/cputype.h>
@ -32,7 +33,6 @@
#include <asm/smp_plat.h>
#include "irq-gic-common.h"
#include "irqchip.h"
struct redist_region {
void __iomem *redist_base;

View File

@ -38,6 +38,7 @@
#include <linux/interrupt.h>
#include <linux/percpu.h>
#include <linux/slab.h>
#include <linux/irqchip.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/irqchip/arm-gic-acpi.h>
@ -48,7 +49,6 @@
#include <asm/smp_plat.h>
#include "irq-gic-common.h"
#include "irqchip.h"
union gic_base {
void __iomem *common_base;
@ -288,8 +288,8 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
{
struct gic_chip_data *chip_data = irq_get_handler_data(irq);
struct irq_chip *chip = irq_get_chip(irq);
struct gic_chip_data *chip_data = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned int cascade_irq, gic_irq;
unsigned long status;
@ -324,16 +324,17 @@ static struct irq_chip gic_chip = {
#endif
.irq_get_irqchip_state = gic_irq_get_irqchip_state,
.irq_set_irqchip_state = gic_irq_set_irqchip_state,
.flags = IRQCHIP_SET_TYPE_MASKED,
.flags = IRQCHIP_SET_TYPE_MASKED |
IRQCHIP_SKIP_SET_WAKE |
IRQCHIP_MASK_ON_SUSPEND,
};
void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
{
if (gic_nr >= MAX_GIC_NR)
BUG();
if (irq_set_handler_data(irq, &gic_data[gic_nr]) != 0)
BUG();
irq_set_chained_handler(irq, gic_handle_cascade_irq);
irq_set_chained_handler_and_data(irq, gic_handle_cascade_irq,
&gic_data[gic_nr]);
}
static u8 gic_get_cpumask(struct gic_chip_data *gic)
@ -355,9 +356,9 @@ static u8 gic_get_cpumask(struct gic_chip_data *gic)
return mask;
}
static void gic_cpu_if_up(void)
static void gic_cpu_if_up(struct gic_chip_data *gic)
{
void __iomem *cpu_base = gic_data_cpu_base(&gic_data[0]);
void __iomem *cpu_base = gic_data_cpu_base(gic);
u32 bypass = 0;
/*
@ -401,34 +402,47 @@ static void gic_cpu_init(struct gic_chip_data *gic)
int i;
/*
* Get what the GIC says our CPU mask is.
* Setting up the CPU map is only relevant for the primary GIC
* because any nested/secondary GICs do not directly interface
* with the CPU(s).
*/
BUG_ON(cpu >= NR_GIC_CPU_IF);
cpu_mask = gic_get_cpumask(gic);
gic_cpu_map[cpu] = cpu_mask;
if (gic == &gic_data[0]) {
/*
* Get what the GIC says our CPU mask is.
*/
BUG_ON(cpu >= NR_GIC_CPU_IF);
cpu_mask = gic_get_cpumask(gic);
gic_cpu_map[cpu] = cpu_mask;
/*
* Clear our mask from the other map entries in case they're
* still undefined.
*/
for (i = 0; i < NR_GIC_CPU_IF; i++)
if (i != cpu)
gic_cpu_map[i] &= ~cpu_mask;
/*
* Clear our mask from the other map entries in case they're
* still undefined.
*/
for (i = 0; i < NR_GIC_CPU_IF; i++)
if (i != cpu)
gic_cpu_map[i] &= ~cpu_mask;
}
gic_cpu_config(dist_base, NULL);
writel_relaxed(GICC_INT_PRI_THRESHOLD, base + GIC_CPU_PRIMASK);
gic_cpu_if_up();
gic_cpu_if_up(gic);
}
void gic_cpu_if_down(void)
int gic_cpu_if_down(unsigned int gic_nr)
{
void __iomem *cpu_base = gic_data_cpu_base(&gic_data[0]);
void __iomem *cpu_base;
u32 val = 0;
if (gic_nr >= MAX_GIC_NR)
return -EINVAL;
cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
val = readl(cpu_base + GIC_CPU_CTRL);
val &= ~GICC_ENABLE;
writel_relaxed(val, cpu_base + GIC_CPU_CTRL);
return 0;
}
#ifdef CONFIG_CPU_PM
@ -564,7 +578,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
dist_base + GIC_DIST_PRI + i * 4);
writel_relaxed(GICC_INT_PRI_THRESHOLD, cpu_base + GIC_CPU_PRIMASK);
gic_cpu_if_up();
gic_cpu_if_up(&gic_data[gic_nr]);
}
static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v)
@ -880,11 +894,6 @@ static const struct irq_domain_ops gic_irq_domain_ops = {
.xlate = gic_irq_domain_xlate,
};
void gic_set_irqchip_flags(unsigned long flags)
{
gic_chip.flags |= flags;
}
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
void __iomem *dist_base, void __iomem *cpu_base,
u32 percpu_offset, struct device_node *node)
@ -929,13 +938,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
gic_set_base_accessor(gic, gic_get_common_base);
}
/*
* Initialize the CPU interface map to all CPUs.
* It will be refined as each CPU probes its ID.
*/
for (i = 0; i < NR_GIC_CPU_IF; i++)
gic_cpu_map[i] = 0xff;
/*
* Find out how many interrupts are supported.
* The GIC only supports up to 1020 interrupt sources.
@ -981,6 +983,13 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
return;
if (gic_nr == 0) {
/*
* Initialize the CPU interface map to all CPUs.
* It will be refined as each CPU probes its ID.
* This is only necessary for the primary GIC.
*/
for (i = 0; i < NR_GIC_CPU_IF; i++)
gic_cpu_map[i] = 0xff;
#ifdef CONFIG_SMP
set_smp_cross_call(gic_raise_softirq);
register_cpu_notifier(&gic_cpu_notifier);

View File

@ -41,6 +41,7 @@
#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/irqchip.h>
#include <linux/irqchip/arm-gic.h>
#include <asm/irq.h>
@ -48,7 +49,6 @@
#include <asm/smp_plat.h>
#include "irq-gic-common.h"
#include "irqchip.h"
#define HIP04_MAX_IRQS 510
@ -202,7 +202,9 @@ static struct irq_chip hip04_irq_chip = {
#ifdef CONFIG_SMP
.irq_set_affinity = hip04_irq_set_affinity,
#endif
.flags = IRQCHIP_SET_TYPE_MASKED,
.flags = IRQCHIP_SET_TYPE_MASKED |
IRQCHIP_SKIP_SET_WAKE |
IRQCHIP_MASK_ON_SUSPEND,
};
static u16 hip04_get_cpumask(struct hip04_irq_data *intc)

View File

@ -12,6 +12,7 @@
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/irqchip.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
#include <linux/of_irq.h>
@ -22,8 +23,6 @@
#include <asm/i8259.h>
#include <asm/io.h>
#include "../../drivers/irqchip/irqchip.h"
/*
* This is the 'legacy' 8259A Programmable Interrupt Controller,
* present in the majority of PC/AT boxes.
@ -353,10 +352,11 @@ void __init init_i8259_irqs(void)
__init_i8259_irqs(NULL);
}
static void i8259_irq_dispatch(unsigned int irq, struct irq_desc *desc)
static void i8259_irq_dispatch(unsigned int __irq, struct irq_desc *desc)
{
struct irq_domain *domain = irq_get_handler_data(irq);
struct irq_domain *domain = irq_desc_get_handler_data(desc);
int hwirq = i8259_irq();
unsigned int irq;
if (hwirq < 0)
return;

View File

@ -218,8 +218,9 @@ static int pdc_irq_set_wake(struct irq_data *data, unsigned int on)
return 0;
}
static void pdc_intc_perip_isr(unsigned int irq, struct irq_desc *desc)
static void pdc_intc_perip_isr(unsigned int __irq, struct irq_desc *desc)
{
unsigned int irq = irq_desc_get_irq(desc);
struct pdc_intc_priv *priv;
unsigned int i, irq_no;
@ -451,13 +452,13 @@ static int pdc_intc_probe(struct platform_device *pdev)
/* Setup chained handlers for the peripheral IRQs */
for (i = 0; i < priv->nr_perips; ++i) {
irq = priv->perip_irqs[i];
irq_set_handler_data(irq, priv);
irq_set_chained_handler(irq, pdc_intc_perip_isr);
irq_set_chained_handler_and_data(irq, pdc_intc_perip_isr,
priv);
}
/* Setup chained handler for the syswake IRQ */
irq_set_handler_data(priv->syswake_irq, priv);
irq_set_chained_handler(priv->syswake_irq, pdc_intc_syswake_isr);
irq_set_chained_handler_and_data(priv->syswake_irq,
pdc_intc_syswake_isr, priv);
dev_info(&pdev->dev,
"PDC IRQ controller initialised (%u perip IRQs, %u syswake IRQs)\n",

View File

@ -0,0 +1,278 @@
/*
* Copyright (C) 2015 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/irqchip.h>
#include <linux/syscore_ops.h>
#define IMR_NUM 4
#define GPC_MAX_IRQS (IMR_NUM * 32)
#define GPC_IMR1_CORE0 0x30
#define GPC_IMR1_CORE1 0x40
struct gpcv2_irqchip_data {
struct raw_spinlock rlock;
void __iomem *gpc_base;
u32 wakeup_sources[IMR_NUM];
u32 saved_irq_mask[IMR_NUM];
u32 cpu2wakeup;
};
static struct gpcv2_irqchip_data *imx_gpcv2_instance;
/*
* Interface for the low level wakeup code.
*/
u32 imx_gpcv2_get_wakeup_source(u32 **sources)
{
if (!imx_gpcv2_instance)
return 0;
if (sources)
*sources = imx_gpcv2_instance->wakeup_sources;
return IMR_NUM;
}
static int gpcv2_wakeup_source_save(void)
{
struct gpcv2_irqchip_data *cd;
void __iomem *reg;
int i;
cd = imx_gpcv2_instance;
if (!cd)
return 0;
for (i = 0; i < IMR_NUM; i++) {
reg = cd->gpc_base + cd->cpu2wakeup + i * 4;
cd->saved_irq_mask[i] = readl_relaxed(reg);
writel_relaxed(cd->wakeup_sources[i], reg);
}
return 0;
}
static void gpcv2_wakeup_source_restore(void)
{
struct gpcv2_irqchip_data *cd;
void __iomem *reg;
int i;
cd = imx_gpcv2_instance;
if (!cd)
return;
for (i = 0; i < IMR_NUM; i++) {
reg = cd->gpc_base + cd->cpu2wakeup + i * 4;
writel_relaxed(cd->saved_irq_mask[i], reg);
}
}
static struct syscore_ops imx_gpcv2_syscore_ops = {
.suspend = gpcv2_wakeup_source_save,
.resume = gpcv2_wakeup_source_restore,
};
static int imx_gpcv2_irq_set_wake(struct irq_data *d, unsigned int on)
{
struct gpcv2_irqchip_data *cd = d->chip_data;
unsigned int idx = d->hwirq / 32;
unsigned long flags;
void __iomem *reg;
u32 mask, val;
raw_spin_lock_irqsave(&cd->rlock, flags);
reg = cd->gpc_base + cd->cpu2wakeup + idx * 4;
mask = 1 << d->hwirq % 32;
val = cd->wakeup_sources[idx];
cd->wakeup_sources[idx] = on ? (val & ~mask) : (val | mask);
raw_spin_unlock_irqrestore(&cd->rlock, flags);
/*
* Do *not* call into the parent, as the GIC doesn't have any
* wake-up facility...
*/
return 0;
}
static void imx_gpcv2_irq_unmask(struct irq_data *d)
{
struct gpcv2_irqchip_data *cd = d->chip_data;
void __iomem *reg;
u32 val;
raw_spin_lock(&cd->rlock);
reg = cd->gpc_base + cd->cpu2wakeup + d->hwirq / 32 * 4;
val = readl_relaxed(reg);
val &= ~(1 << d->hwirq % 32);
writel_relaxed(val, reg);
raw_spin_unlock(&cd->rlock);
irq_chip_unmask_parent(d);
}
static void imx_gpcv2_irq_mask(struct irq_data *d)
{
struct gpcv2_irqchip_data *cd = d->chip_data;
void __iomem *reg;
u32 val;
raw_spin_lock(&cd->rlock);
reg = cd->gpc_base + cd->cpu2wakeup + d->hwirq / 32 * 4;
val = readl_relaxed(reg);
val |= 1 << (d->hwirq % 32);
writel_relaxed(val, reg);
raw_spin_unlock(&cd->rlock);
irq_chip_mask_parent(d);
}
static struct irq_chip gpcv2_irqchip_data_chip = {
.name = "GPCv2",
.irq_eoi = irq_chip_eoi_parent,
.irq_mask = imx_gpcv2_irq_mask,
.irq_unmask = imx_gpcv2_irq_unmask,
.irq_set_wake = imx_gpcv2_irq_set_wake,
.irq_retrigger = irq_chip_retrigger_hierarchy,
#ifdef CONFIG_SMP
.irq_set_affinity = irq_chip_set_affinity_parent,
#endif
};
static int imx_gpcv2_domain_xlate(struct irq_domain *domain,
struct device_node *controller,
const u32 *intspec,
unsigned int intsize,
unsigned long *out_hwirq,
unsigned int *out_type)
{
/* Shouldn't happen, really... */
if (domain->of_node != controller)
return -EINVAL;
/* Not GIC compliant */
if (intsize != 3)
return -EINVAL;
/* No PPI should point to this domain */
if (intspec[0] != 0)
return -EINVAL;
*out_hwirq = intspec[1];
*out_type = intspec[2];
return 0;
}
static int imx_gpcv2_domain_alloc(struct irq_domain *domain,
unsigned int irq, unsigned int nr_irqs,
void *data)
{
struct of_phandle_args *args = data;
struct of_phandle_args parent_args;
irq_hw_number_t hwirq;
int i;
/* Not GIC compliant */
if (args->args_count != 3)
return -EINVAL;
/* No PPI should point to this domain */
if (args->args[0] != 0)
return -EINVAL;
/* Can't deal with this */
hwirq = args->args[1];
if (hwirq >= GPC_MAX_IRQS)
return -EINVAL;
for (i = 0; i < nr_irqs; i++) {
irq_domain_set_hwirq_and_chip(domain, irq + i, hwirq + i,
&gpcv2_irqchip_data_chip, domain->host_data);
}
parent_args = *args;
parent_args.np = domain->parent->of_node;
return irq_domain_alloc_irqs_parent(domain, irq, nr_irqs, &parent_args);
}
static struct irq_domain_ops gpcv2_irqchip_data_domain_ops = {
.xlate = imx_gpcv2_domain_xlate,
.alloc = imx_gpcv2_domain_alloc,
.free = irq_domain_free_irqs_common,
};
static int __init imx_gpcv2_irqchip_init(struct device_node *node,
struct device_node *parent)
{
struct irq_domain *parent_domain, *domain;
struct gpcv2_irqchip_data *cd;
int i;
if (!parent) {
pr_err("%s: no parent, giving up\n", node->full_name);
return -ENODEV;
}
parent_domain = irq_find_host(parent);
if (!parent_domain) {
pr_err("%s: unable to get parent domain\n", node->full_name);
return -ENXIO;
}
cd = kzalloc(sizeof(struct gpcv2_irqchip_data), GFP_KERNEL);
if (!cd) {
pr_err("kzalloc failed!\n");
return -ENOMEM;
}
cd->gpc_base = of_iomap(node, 0);
if (!cd->gpc_base) {
pr_err("fsl-gpcv2: unable to map gpc registers\n");
kfree(cd);
return -ENOMEM;
}
domain = irq_domain_add_hierarchy(parent_domain, 0, GPC_MAX_IRQS,
node, &gpcv2_irqchip_data_domain_ops, cd);
if (!domain) {
iounmap(cd->gpc_base);
kfree(cd);
return -ENOMEM;
}
irq_set_default_host(domain);
/* Initially mask all interrupts */
for (i = 0; i < IMR_NUM; i++) {
writel_relaxed(~0, cd->gpc_base + GPC_IMR1_CORE0 + i * 4);
writel_relaxed(~0, cd->gpc_base + GPC_IMR1_CORE1 + i * 4);
cd->wakeup_sources[i] = ~0;
}
/* Let CORE0 as the default CPU to wake up by GPC */
cd->cpu2wakeup = GPC_IMR1_CORE0;
/*
* Due to hardware design failure, need to make sure GPR
* interrupt(#32) is unmasked during RUN mode to avoid entering
* DSM by mistake.
*/
writel_relaxed(~0x1, cd->gpc_base + cd->cpu2wakeup);
imx_gpcv2_instance = cd;
register_syscore_ops(&imx_gpcv2_syscore_ops);
return 0;
}
IRQCHIP_DECLARE(imx_gpcv2, "fsl,imx7d-gpc", imx_gpcv2_irqchip_init);

View File

@ -18,6 +18,7 @@
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/irqchip.h>
#include <linux/irqchip/ingenic.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@ -28,8 +29,6 @@
#include <asm/io.h>
#include <asm/mach-jz4740/irq.h>
#include "irqchip.h"
struct ingenic_intc_data {
void __iomem *base;
unsigned num_chips;

View File

@ -20,13 +20,12 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/irqdomain.h>
#include <linux/irqchip.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include "irqchip.h"
/* The source ID bits start from 4 to 31 (total 28 bits)*/
#define BIT_OFS 4
@ -84,8 +83,9 @@ static void keystone_irq_ack(struct irq_data *d)
/* nothing to do here */
}
static void keystone_irq_handler(unsigned irq, struct irq_desc *desc)
static void keystone_irq_handler(unsigned __irq, struct irq_desc *desc)
{
unsigned int irq = irq_desc_get_irq(desc);
struct keystone_irq_device *kirq = irq_desc_get_handler_data(desc);
unsigned long pending;
int src, virq;

View File

@ -404,7 +404,6 @@ static int meta_intc_irq_set_type(struct irq_data *data, unsigned int flow_type)
#ifdef CONFIG_METAG_SUSPEND_MEM
struct meta_intc_priv *priv = &meta_intc_priv;
#endif
unsigned int irq = data->irq;
irq_hw_number_t hw = data->hwirq;
unsigned int bit = 1 << meta_intc_offset(hw);
void __iomem *level_addr = meta_intc_level_addr(hw);
@ -413,11 +412,11 @@ static int meta_intc_irq_set_type(struct irq_data *data, unsigned int flow_type)
/* update the chip/handler */
if (flow_type & IRQ_TYPE_LEVEL_MASK)
__irq_set_chip_handler_name_locked(irq, &meta_intc_level_chip,
handle_level_irq, NULL);
irq_set_chip_handler_name_locked(data, &meta_intc_level_chip,
handle_level_irq, NULL);
else
__irq_set_chip_handler_name_locked(irq, &meta_intc_edge_chip,
handle_edge_irq, NULL);
irq_set_chip_handler_name_locked(data, &meta_intc_edge_chip,
handle_edge_irq, NULL);
/* and clear/set the bit in HWLEVELEXT */
__global_lock2(flags);

View File

@ -286,8 +286,7 @@ static void metag_internal_irq_init_cpu(struct metag_internal_irq_priv *priv,
int irq = tbisig_map(signum);
/* Register the multiplexed IRQ handler */
irq_set_handler_data(irq, priv);
irq_set_chained_handler(irq, metag_internal_irq_demux);
irq_set_chained_handler_and_data(irq, metag_internal_irq_demux, priv);
irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
}

View File

@ -31,6 +31,7 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/irqdomain.h>
#include <asm/irq_cpu.h>
@ -38,8 +39,6 @@
#include <asm/mipsmtregs.h>
#include <asm/setup.h>
#include "irqchip.h"
static inline void unmask_mips_irq(struct irq_data *d)
{
set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE));

View File

@ -11,6 +11,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/irqchip/mips-gic.h>
#include <linux/of_address.h>
#include <linux/sched.h>
@ -22,8 +23,6 @@
#include <dt-bindings/interrupt-controller/mips-gic.h>
#include "irqchip.h"
unsigned int gic_present;
struct gic_pcpu_mask {
@ -358,15 +357,12 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
break;
}
if (is_edge) {
__irq_set_chip_handler_name_locked(d->irq,
&gic_edge_irq_controller,
handle_edge_irq, NULL);
} else {
__irq_set_chip_handler_name_locked(d->irq,
&gic_level_irq_controller,
handle_level_irq, NULL);
}
if (is_edge)
irq_set_chip_handler_name_locked(d, &gic_edge_irq_controller,
handle_edge_irq, NULL);
else
irq_set_chip_handler_name_locked(d, &gic_level_irq_controller,
handle_level_irq, NULL);
spin_unlock_irqrestore(&gic_lock, flags);
return 0;
@ -396,7 +392,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
clear_bit(irq, pcpu_masks[i].pcpu_mask);
set_bit(irq, pcpu_masks[cpumask_first(&tmp)].pcpu_mask);
cpumask_copy(d->affinity, cpumask);
cpumask_copy(irq_data_get_affinity_mask(d), cpumask);
spin_unlock_irqrestore(&gic_lock, flags);
return IRQ_SET_MASK_OK_NOCOPY;

Some files were not shown because too many files have changed in this diff Show More