2 * arch/arm/mach-mx6/msi.c
4 * PCI MSI support for the imx processor
6 * Copyright (c) 2013, Boundary Devices.
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place - Suite 330, Boston, MA 02111-1307 USA.
22 #include <linux/module.h>
23 #include <linux/pci.h>
24 #include <linux/msi.h>
25 #include <asm/bitops.h>
26 #include <asm/mach/irq.h>
28 #include <linux/irqchip/chained_irq.h>
33 #define IMX_NUM_MSI_IRQS 128
34 static DECLARE_BITMAP(msi_irq_in_use
, IMX_NUM_MSI_IRQS
);
37 static void imx_msi_handler(unsigned int irq
, struct irq_desc
*desc
)
41 struct irq_chip
*chip
= irq_get_chip(irq
);
43 irq_base
= irq_alloc_descs(-1, 0, IMX_NUM_MSI_IRQS
, 0);
45 printk(KERN_ERR
"%s: could not allocate IRQ numbers\n", __func__
);
49 chained_irq_enter(chip
, desc
);
50 for (i
= 0; i
< 8; i
++) {
51 status
= imx_pcie_msi_pending(i
);
54 generic_handle_irq(irq_base
+ j
);
59 chained_irq_exit(chip
, desc
);
63 * Dynamic irq allocate and deallocation
70 pos
= find_first_zero_bit(msi_irq_in_use
, IMX_NUM_MSI_IRQS
);
71 if ((unsigned)pos
>= IMX_NUM_MSI_IRQS
)
73 /* test_and_set_bit operates on 32-bits at a time */
74 } while (test_and_set_bit(pos
, msi_irq_in_use
));
77 dynamic_irq_init(irq
);
81 void destroy_irq(unsigned int irq
)
83 int pos
= irq
- irq_base
;
85 dynamic_irq_cleanup(irq
);
86 clear_bit(pos
, msi_irq_in_use
);
89 void arch_teardown_msi_irq(unsigned int irq
)
94 static void imx_msi_irq_ack(struct irq_data
*d
)
99 static void imx_msi_irq_enable(struct irq_data
*d
)
101 imx_pcie_enable_irq(d
->irq
- irq_base
, 1);
102 return unmask_msi_irq(d
);
105 static void imx_msi_irq_disable(struct irq_data
*d
)
107 imx_pcie_enable_irq(d
->irq
- irq_base
, 0);
108 return mask_msi_irq(d
);
111 static void imx_msi_irq_mask(struct irq_data
*d
)
113 imx_pcie_mask_irq(d
->irq
- irq_base
, 1);
114 return mask_msi_irq(d
);
117 static void imx_msi_irq_unmask(struct irq_data
*d
)
119 imx_pcie_mask_irq(d
->irq
- irq_base
, 0);
120 return unmask_msi_irq(d
);
123 static struct irq_chip imx_msi_chip
= {
125 .irq_ack
= imx_msi_irq_ack
,
126 .irq_enable
= imx_msi_irq_enable
,
127 .irq_disable
= imx_msi_irq_disable
,
128 .irq_mask
= imx_msi_irq_mask
,
129 .irq_unmask
= imx_msi_irq_unmask
,
132 int arch_setup_msi_irq(struct pci_dev
*pdev
, struct msi_desc
*desc
)
134 int irq
= create_irq();
140 irq_set_msi_desc(irq
, desc
);
142 msg
.address_hi
= 0x0;
143 msg
.address_lo
= MSI_MATCH_ADDR
;
144 msg
.data
= (mxc_cpu_type
<< 15) | ((irq
- irq_base
) & 0xff);
146 write_msi_msg(irq
, &msg
);
147 irq_set_chip_and_handler(irq
, &imx_msi_chip
, handle_simple_irq
);
148 set_irq_flags(irq
, IRQF_VALID
);
149 pr_info("%s: %d of %d\n", __func__
, irq
, NR_IRQS
);
153 void imx_msi_init(void)
155 irq_set_chained_handler(MXC_INT_PCIE_0
, imx_msi_handler
);