Hi,
This patch series moves the Xilinx interrupt controller driver out
of arch/microblaze to drivers/irqchip and then cleans it up a bit.
And then removes another implementation of the driver in arch/powerpc.
This effort results in one common driver usable by mips,microblaze
and powerpc.
Compile tested on microblaze-el.
Tested using qemu-system-ppc using virtix440-ml507
Tested on MIPSfpga platform.
Based on v4.9-rc5
Thanks,
ZubairLK
V6 -> V7
Rebase to v4.5-rc5
Split print messages cleanup into a separate patch
Use jump label api to restructure read/write handling in driver.
V5 -> V6
Split patch series. Patches for arch/mips can go separately
Rebase to v4.9-rc3
Added chained_irq_enter/exit
Removed __func__ used in pr_err
V4 -> V5
Added a new patch that removes the PPC driver
Rebase to v4.9-rc1
Better error handling
V3 -> V4
Better error handling
Some minor fixups
V2 -> V3
Cleanup the interrupt controller driver a bit based on feedback
Rebase to v4.8-rc4
V1 -> V2
Resubmitting without truncating the diff output for file moves
Removed accidental local mac address entry
Individual logs have more detail
Zubair Lutfullah Kakakhel (7):
microblaze: irqchip: Move intc driver to irqchip
irqchip: xilinx: clean up print messages
irqchip: xilinx: restructure and use jump label api
irqchip: xilinx: Rename get_irq to xintc_get_irq
irqchip: xilinx: Add support for parent intc
irqchip: xilinx: Try to fall back if xlnx,kind-of-intr not provided
powerpc/virtex: Use generic xilinx irqchip driver
arch/microblaze/Kconfig | 1 +
arch/microblaze/include/asm/irq.h | 2 +-
arch/microblaze/kernel/Makefile | 2 +-
arch/microblaze/kernel/intc.c | 196 ---------------------------
arch/microblaze/kernel/irq.c | 4 +-
arch/powerpc/include/asm/xilinx_intc.h | 2 +-
arch/powerpc/platforms/40x/Kconfig | 1 +
arch/powerpc/platforms/40x/virtex.c | 2 +-
arch/powerpc/platforms/44x/Kconfig | 1 +
arch/powerpc/platforms/44x/virtex.c | 2 +-
arch/powerpc/sysdev/xilinx_intc.c | 211 +----------------------------
drivers/irqchip/Kconfig | 4 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-xilinx-intc.c | 241 +++++++++++++++++++++++++++++++++
14 files changed, 258 insertions(+), 412 deletions(-)
delete mode 100644 arch/microblaze/kernel/intc.c
create mode 100644 drivers/irqchip/irq-xilinx-intc.c
--
2.10.2
The Xilinx AXI Interrupt Controller IP block is used by the MIPS
based xilfpga platform and a few PowerPC based platforms.
Move the interrupt controller code out of arch/microblaze so that
it can be used by everyone
Signed-off-by: Zubair Lutfullah Kakakhel <redacted>
---
V6 -> V7
Rebase to v4.9-rc5
V5 -> V6
Rebase to v4.9-rc3
V4 -> V5
Rebase to v4.9-rc1
Renamed back to irq-xilinx-intc.c
V3 -> V4
No change
V2 -> V3
No change here. Cleanup patches follow after this patch.
Its debatable to cleanup before/after move. Decided to place cleanup
after move to put history in new place.
V1 -> V2
Renamed irq-xilinx to irq-axi-intc
Renamed CONFIG_XILINX_INTC to CONFIG_XILINX_AXI_INTC
Patch is now without rename flag so as to facilitate review
---
arch/microblaze/Kconfig | 1 +
arch/microblaze/kernel/Makefile | 2 +-
drivers/irqchip/Kconfig | 4 ++++
drivers/irqchip/Makefile | 1 +
arch/microblaze/kernel/intc.c => drivers/irqchip/irq-xilinx-intc.c | 0
5 files changed, 7 insertions(+), 1 deletion(-)
rename arch/microblaze/kernel/intc.c => drivers/irqchip/irq-xilinx-intc.c (100%)
diff --git a/arch/microblaze/kernel/intc.c b/drivers/irqchip/irq-xilinx-intc.csimilarity index 100%rename from arch/microblaze/kernel/intc.crename to drivers/irqchip/irq-xilinx-intc.c
--
2.10.2
@@ -29,194 +29,7 @@#include<asm/processor.h>#include<asm/i8259.h>#include<asm/irq.h>--/*-*INTCRegisters-*/-#define XINTC_ISR 0 /* Interrupt Status */-#define XINTC_IPR 4 /* Interrupt Pending */-#define XINTC_IER 8 /* Interrupt Enable */-#define XINTC_IAR 12 /* Interrupt Acknowledge */-#define XINTC_SIE 16 /* Set Interrupt Enable bits */-#define XINTC_CIE 20 /* Clear Interrupt Enable bits */-#define XINTC_IVR 24 /* Interrupt Vector */-#define XINTC_MER 28 /* Master Enable */--staticstructirq_domain*master_irqhost;--#define XILINX_INTC_MAXIRQS (32)--/* The following table allows the interrupt type, edge or level,-*tobecachedafterbeingreadfromthedevicetreeuntiltheinterrupt-*ismapped-*/-staticintxilinx_intc_typetable[XILINX_INTC_MAXIRQS];--/* Map the interrupt type from the device tree to the interrupt types-*usedbytheinterruptsubsystem-*/-staticunsignedcharxilinx_intc_map_senses[]={-IRQ_TYPE_EDGE_RISING,-IRQ_TYPE_EDGE_FALLING,-IRQ_TYPE_LEVEL_HIGH,-IRQ_TYPE_LEVEL_LOW,-};--/*-*Theinterruptcontrollerissetupsuchthatitdoesn'tworkwellwith-*thelevelinterrupthandlerinthekernelbecausethehandleracksthe-*interruptbeforecallingtheapplicationinterrupthandler.Todealwith-*that,weuse2differentirqchipssothatdifferentfunctionscanbe-*usedforlevelandedgetypeinterrupts.-*-*IRQChipcommon(acrosslevelandedge)operations-*/-staticvoidxilinx_intc_mask(structirq_data*d)-{-intirq=irqd_to_hwirq(d);-void*regs=irq_data_get_irq_chip_data(d);-pr_debug("mask: %d\n",irq);-out_be32(regs+XINTC_CIE,1<<irq);-}--staticintxilinx_intc_set_type(structirq_data*d,unsignedintflow_type)-{-return0;-}--/*-*IRQChipleveloperations-*/-staticvoidxilinx_intc_level_unmask(structirq_data*d)-{-intirq=irqd_to_hwirq(d);-void*regs=irq_data_get_irq_chip_data(d);-pr_debug("unmask: %d\n",irq);-out_be32(regs+XINTC_SIE,1<<irq);--/* ack level irqs because they can't be acked during-*ackfunctionsincethehandle_level_irqfunction-*ackstheirqbeforecallingtheinerrupthandler-*/-out_be32(regs+XINTC_IAR,1<<irq);-}--staticstructirq_chipxilinx_intc_level_irqchip={-.name="Xilinx Level INTC",-.irq_mask=xilinx_intc_mask,-.irq_mask_ack=xilinx_intc_mask,-.irq_unmask=xilinx_intc_level_unmask,-.irq_set_type=xilinx_intc_set_type,-};--/*-*IRQChipedgeoperations-*/-staticvoidxilinx_intc_edge_unmask(structirq_data*d)-{-intirq=irqd_to_hwirq(d);-void*regs=irq_data_get_irq_chip_data(d);-pr_debug("unmask: %d\n",irq);-out_be32(regs+XINTC_SIE,1<<irq);-}--staticvoidxilinx_intc_edge_ack(structirq_data*d)-{-intirq=irqd_to_hwirq(d);-void*regs=irq_data_get_irq_chip_data(d);-pr_debug("ack: %d\n",irq);-out_be32(regs+XINTC_IAR,1<<irq);-}--staticstructirq_chipxilinx_intc_edge_irqchip={-.name="Xilinx Edge INTC",-.irq_mask=xilinx_intc_mask,-.irq_unmask=xilinx_intc_edge_unmask,-.irq_ack=xilinx_intc_edge_ack,-.irq_set_type=xilinx_intc_set_type,-};--/*-*IRQHostoperations-*/--/**-*xilinx_intc_xlate-translatevirq#fromdevicetreeinterruptsproperty-*/-staticintxilinx_intc_xlate(structirq_domain*h,structdevice_node*ct,-constu32*intspec,unsignedintintsize,-irq_hw_number_t*out_hwirq,-unsignedint*out_flags)-{-if((intsize<2)||(intspec[0]>=XILINX_INTC_MAXIRQS))-return-EINVAL;--/* keep a copy of the interrupt type til the interrupt is mapped-*/-xilinx_intc_typetable[intspec[0]]=xilinx_intc_map_senses[intspec[1]];--/* Xilinx uses 2 interrupt entries, the 1st being the h/w-*interruptnumber,the2ndbeingtheinterrupttype,edgeorlevel-*/-*out_hwirq=intspec[0];-*out_flags=xilinx_intc_map_senses[intspec[1]];--return0;-}-staticintxilinx_intc_map(structirq_domain*h,unsignedintvirq,-irq_hw_number_tirq)-{-irq_set_chip_data(virq,h->host_data);--if(xilinx_intc_typetable[irq]==IRQ_TYPE_LEVEL_HIGH||-xilinx_intc_typetable[irq]==IRQ_TYPE_LEVEL_LOW){-irq_set_chip_and_handler(virq,&xilinx_intc_level_irqchip,-handle_level_irq);-}else{-irq_set_chip_and_handler(virq,&xilinx_intc_edge_irqchip,-handle_edge_irq);-}-return0;-}--staticconststructirq_domain_opsxilinx_intc_ops={-.map=xilinx_intc_map,-.xlate=xilinx_intc_xlate,-};--structirq_domain*__init-xilinx_intc_init(structdevice_node*np)-{-structirq_domain*irq;-void*regs;--/* Find and map the intc registers */-regs=of_iomap(np,0);-if(!regs){-pr_err("xilinx_intc: could not map registers\n");-returnNULL;-}--/* Setup interrupt controller */-out_be32(regs+XINTC_IER,0);/* disable all irqs */-out_be32(regs+XINTC_IAR,~(u32)0);/* Acknowledge pending irqs */-out_be32(regs+XINTC_MER,0x3UL);/* Turn on the Master Enable. */--/* Allocate and initialize an irq_domain structure. */-irq=irq_domain_add_linear(np,XILINX_INTC_MAXIRQS,&xilinx_intc_ops,-regs);-if(!irq)-panic(__FILE__": Cannot allocate IRQ host\n");--returnirq;-}--intxilinx_intc_get_irq(void)-{-void*regs=master_irqhost->host_data;-pr_debug("get_irq:\n");-returnirq_linear_revmap(master_irqhost,in_be32(regs+XINTC_IVR));-}+#include<linux/irqchip.h>#if defined(CONFIG_PPC_I8259)/*
The MIPS based xilfpga platform has the following IRQ structure
Peripherals --> xilinx_intcontroller -> mips_cpu_int controller
Add support for the driver to chain the irq handler
Signed-off-by: Zubair Lutfullah Kakakhel <redacted>
---
V6 -> V7
Rebase to v4.9-rc5
V5 -> V6
Use chained_irq_enter and chained_irq_exit
Add error check for irq_of_parse_and_map
Rebase to v4.9-rc3
V4 -> V5
Rebased to v4.9-rc1
Missing curly braces
V3 -> V4
Clean up if/else when a parent is found
Pass irqchip structure to handler as data
V2 -> V3
Reused existing parent node instead of finding again.
Cleanup up handler based on review
V1 -> V2
No change
---
drivers/irqchip/irq-xilinx-intc.c | 34 ++++++++++++++++++++++++++++++++--
1 file changed, 32 insertions(+), 2 deletions(-)
@@ -12,10 +12,12 @@#include<linux/irqdomain.h>#include<linux/irq.h>#include<linux/irqchip.h>+#include<linux/irqchip/chained_irq.h>#include<linux/of_address.h>#include<linux/io.h>#include<linux/jump_label.h>#include<linux/bug.h>+#include<linux/of_irq.h>/* No one else should require these constants, so define them locally here. */#define ISR 0x00 /* Interrupt Status Register */
@@ -196,7 +213,20 @@ static int __init xilinx_intc_of_init(struct device_node *intc,gotoerr_alloc;}-irq_set_default_host(irqc->root_domain);+if(parent){+irq=irq_of_parse_and_map(intc,0);+if(irq){+irq_set_chained_handler_and_data(irq,+xil_intc_irq_handler,+irqc);+}else{+pr_err("irq-xilinx: interrupts property not in DT\n");+ret=-EINVAL;+gotoerr_alloc;+}+}else{+irq_set_default_host(irqc->root_domain);+}return0;
The powerpc dts file does not have the xlnx,kind-of-intr property.
Instead of erroring out, give a warning instead. And attempt to
continue to probe the interrupt controller while assuming
kind-of-intr is 0x0 as a fall back.
Signed-off-by: Zubair Lutfullah Kakakhel <redacted>
---
V6 -> V7
Rebase to v4.9-rc5
V5 -> V6
Rebase to v4.9-rc3
V5 new patch
---
drivers/irqchip/irq-xilinx-intc.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
Add a global structure to house various variables.
And cleanup read/write handling by using jump label api.
Signed-off-by: Zubair Lutfullah Kakakhel <redacted>
---
V6 -> V7
Restructure and use jump label api
Better commit log
V5 -> V6
Removed __func__ from printk
Rebase to v4.9-rc3
V4 -> V5
Rebased to v4.9-rc1
Better error handling
V3 -> V4
Better error handling for kzalloc
Erroring out if the axi intc is probed twice as that isn't
supported
V2 -> V3
New patch. Cleans up driver structure
---
drivers/irqchip/irq-xilinx-intc.c | 118 +++++++++++++++++++++-----------------
1 file changed, 66 insertions(+), 52 deletions(-)
@@ -14,10 +14,9 @@#include<linux/irqchip.h>#include<linux/of_address.h>#include<linux/io.h>+#include<linux/jump_label.h>#include<linux/bug.h>-staticvoid__iomem*intc_baseaddr;-/* No one else should require these constants, so define them locally here. */#define ISR 0x00 /* Interrupt Status Register */#define IPR 0x04 /* Interrupt Pending Register */
@@ -116,9 +116,7 @@ unsigned int get_irq(void)staticintxintc_map(structirq_domain*d,unsignedintirq,irq_hw_number_thw){-u32intr_mask=(u32)d->host_data;--if(intr_mask&(1<<hw)){+if(xintc_irqc->intr_mask&(1<<hw)){irq_set_chip_and_handler_name(irq,&intc_dev,handle_edge_irq,"edge");irq_clear_status_flags(irq,IRQ_LEVEL);
@@ -138,59 +136,75 @@ static const struct irq_domain_ops xintc_irq_domain_ops = {staticint__initxilinx_intc_of_init(structdevice_node*intc,structdevice_node*parent){-u32nr_irq,intr_mask;+u32nr_irq;intret;+structxintc_irq_chip*irqc;-intc_baseaddr=of_iomap(intc,0);-BUG_ON(!intc_baseaddr);+if(xintc_irqc){+pr_err("irq-xilinx: Multiple instances aren't supported\n");+return-EINVAL;+}++irqc=kzalloc(sizeof(*irqc),GFP_KERNEL);+if(!irqc)+return-ENOMEM;++xintc_irqc=irqc;++irqc->base=of_iomap(intc,0);+BUG_ON(!irqc->base);ret=of_property_read_u32(intc,"xlnx,num-intr-inputs",&nr_irq);if(ret<0){pr_err("irq-xilinx: unable to read xlnx,num-intr-inputs\n");-returnret;+gotoerr_alloc;}-ret=of_property_read_u32(intc,"xlnx,kind-of-intr",&intr_mask);+ret=of_property_read_u32(intc,"xlnx,kind-of-intr",&irqc->intr_mask);if(ret<0){pr_err("irq-xilinx: unable to read xlnx,kind-of-intr\n");-returnret;+gotoerr_alloc;}-if(intr_mask>>nr_irq)+if(irqc->intr_mask>>nr_irq)pr_warn("irq-xilinx: mismatch in kind-of-intr param\n");pr_info("irq-xilinx: %s: num_irq=%d, edge=0x%x\n",-intc->full_name,nr_irq,intr_mask);+intc->full_name,nr_irq,irqc->intr_mask);-write_fn=intc_write32;-read_fn=intc_read32;/**Disableallexternalinterruptsuntiltheyare*explicityrequested.*/-write_fn(0,intc_baseaddr+IER);+xintc_write(IER,0);/* Acknowledge any pending interrupts just in case. */-write_fn(0xffffffff,intc_baseaddr+IAR);+xintc_write(IAR,0xffffffff);/* Turn on the Master Enable. */-write_fn(MER_HIE|MER_ME,intc_baseaddr+MER);-if(!(read_fn(intc_baseaddr+MER)&(MER_HIE|MER_ME))){-write_fn=intc_write32_be;-read_fn=intc_read32_be;-write_fn(MER_HIE|MER_ME,intc_baseaddr+MER);+xintc_write(MER,MER_HIE|MER_ME);+if(!(xintc_read(MER)&(MER_HIE|MER_ME))){+static_branch_enable(&xintc_is_be);+xintc_write(MER,MER_HIE|MER_ME);}-/* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm-*lazyandMichalcancleanituptosomethingnicerwhenhetests-*andcommitsthispatch.~~gcl*/-root_domain=irq_domain_add_linear(intc,nr_irq,&xintc_irq_domain_ops,-(void*)intr_mask);+irqc->root_domain=irq_domain_add_linear(intc,nr_irq,+&xintc_irq_domain_ops,irqc);+if(!irqc->root_domain){+pr_err("irq-xilinx: Unable to create IRQ domain\n");+gotoerr_alloc;+}-irq_set_default_host(root_domain);+irq_set_default_host(irqc->root_domain);return0;++err_alloc:+xintc_irqc=NULL;+kfree(irqc);+returnret;+}IRQCHIP_DECLARE(xilinx_intc,"xlnx,xps-intc-1.00.a",xilinx_intc_of_init);
Now that the driver is generic and used by multiple archs,
get_irq is too generic.
Rename get_irq to xintc_get_irq to avoid any conflicts
Signed-off-by: Zubair Lutfullah Kakakhel <redacted>
---
V6 -> V7
Rebase to v4.9-rc5
V5 -> V6
Removed __func__ in printk
Rebase to v4.9-rc3
V4 -> V5
Rebased to v4.9-rc1
Use __func__ in pr_err
V3 -> V4
New patch.
---
arch/microblaze/include/asm/irq.h | 2 +-
arch/microblaze/kernel/irq.c | 4 ++--
drivers/irqchip/irq-xilinx-intc.c | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
@@ -16,6 +16,6 @@ struct pt_regs;externvoiddo_IRQ(structpt_regs*regs);/* should be defined in each interrupt controller driver */-externunsignedintget_irq(void);+externunsignedintxintc_get_irq(void);#endif /* _ASM_MICROBLAZE_IRQ_H */
Remove __func__ and prefix irq-xilinx in various debug prints
Signed-off-by: Zubair Lutfullah Kakakhel <redacted>
---
V6 -> V7
New patch
This diff was squashed into another patch. Split it up for cleanliness
---
drivers/irqchip/irq-xilinx-intc.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
From: Michal Simek <hidden> Date: 2016-11-15 12:23:10
On 14.11.2016 13:13, Zubair Lutfullah Kakakhel wrote:
quoted hunk
The Xilinx AXI Interrupt Controller IP block is used by the MIPS
based xilfpga platform and a few PowerPC based platforms.
Move the interrupt controller code out of arch/microblaze so that
it can be used by everyone
Signed-off-by: Zubair Lutfullah Kakakhel <redacted>
---
V6 -> V7
Rebase to v4.9-rc5
V5 -> V6
Rebase to v4.9-rc3
V4 -> V5
Rebase to v4.9-rc1
Renamed back to irq-xilinx-intc.c
V3 -> V4
No change
V2 -> V3
No change here. Cleanup patches follow after this patch.
Its debatable to cleanup before/after move. Decided to place cleanup
after move to put history in new place.
V1 -> V2
Renamed irq-xilinx to irq-axi-intc
Renamed CONFIG_XILINX_INTC to CONFIG_XILINX_AXI_INTC
Patch is now without rename flag so as to facilitate review
---
arch/microblaze/Kconfig | 1 +
arch/microblaze/kernel/Makefile | 2 +-
drivers/irqchip/Kconfig | 4 ++++
drivers/irqchip/Makefile | 1 +
arch/microblaze/kernel/intc.c => drivers/irqchip/irq-xilinx-intc.c | 0
5 files changed, 7 insertions(+), 1 deletion(-)
rename arch/microblaze/kernel/intc.c => drivers/irqchip/irq-xilinx-intc.c (100%)
diff --git a/arch/microblaze/kernel/intc.c b/drivers/irqchip/irq-xilinx-intc.csimilarity index 100%rename from arch/microblaze/kernel/intc.crename to drivers/irqchip/irq-xilinx-intc.c
From: Michal Simek <hidden> Date: 2016-11-15 12:38:56
On 14.11.2016 13:13, Zubair Lutfullah Kakakhel wrote:
quoted hunk
Remove __func__ and prefix irq-xilinx in various debug prints
Signed-off-by: Zubair Lutfullah Kakakhel <redacted>
---
V6 -> V7
New patch
This diff was squashed into another patch. Split it up for cleanliness
---
drivers/irqchip/irq-xilinx-intc.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
From: Michal Simek <hidden> Date: 2016-11-15 12:49:20
On 14.11.2016 13:13, Zubair Lutfullah Kakakhel wrote:
quoted hunk
Add a global structure to house various variables.
And cleanup read/write handling by using jump label api.
Signed-off-by: Zubair Lutfullah Kakakhel <redacted>
---
V6 -> V7
Restructure and use jump label api
Better commit log
V5 -> V6
Removed __func__ from printk
Rebase to v4.9-rc3
V4 -> V5
Rebased to v4.9-rc1
Better error handling
V3 -> V4
Better error handling for kzalloc
Erroring out if the axi intc is probed twice as that isn't
supported
V2 -> V3
New patch. Cleans up driver structure
---
drivers/irqchip/irq-xilinx-intc.c | 118 +++++++++++++++++++++-----------------
1 file changed, 66 insertions(+), 52 deletions(-)
@@ -14,10 +14,9 @@#include<linux/irqchip.h>#include<linux/of_address.h>#include<linux/io.h>+#include<linux/jump_label.h>#include<linux/bug.h>-staticvoid__iomem*intc_baseaddr;-/* No one else should require these constants, so define them locally here. */#define ISR 0x00 /* Interrupt Status Register */#define IPR 0x04 /* Interrupt Pending Register */
I don't agree with this.
Pretty long time ago we were added support for multiple instances in
xilinx private tree.
You can look here.
https://github.com/Xilinx/linux-xlnx/blob/master/drivers/irqchip/irq-xilinx-intc.c
Not sure if this the latest way how to do it but as you can see
we were setting up
irq_set_handler_data(irq, intc);
and then when you need that structure we were calling
struct intc *local_intc = irq_data_get_irq_chip_data(d);
And that should be it to support multiple instance of this driver.
Based on 5/7 you are describing your interrupt subsystem like this.
Peripherals --> xilinx_intcontroller -> mips_cpu_int controller
If mips_cpu_int has more than one input you can connect more xilinx intc
controllers.
If not you still have an option to connect
xilinx_intcontroller(up to 32 peripherals) -> xilinx_intcontroller(one
intc + up to 31 peripherals) -> mips_cpu_int controller
Thanks,
Michal
@@ -29,194 +29,7 @@#include<asm/processor.h>#include<asm/i8259.h>#include<asm/irq.h>--/*-*INTCRegisters-*/-#define XINTC_ISR 0 /* Interrupt Status */-#define XINTC_IPR 4 /* Interrupt Pending */-#define XINTC_IER 8 /* Interrupt Enable */-#define XINTC_IAR 12 /* Interrupt Acknowledge */-#define XINTC_SIE 16 /* Set Interrupt Enable bits */-#define XINTC_CIE 20 /* Clear Interrupt Enable bits */-#define XINTC_IVR 24 /* Interrupt Vector */-#define XINTC_MER 28 /* Master Enable */--staticstructirq_domain*master_irqhost;--#define XILINX_INTC_MAXIRQS (32)--/* The following table allows the interrupt type, edge or level,-*tobecachedafterbeingreadfromthedevicetreeuntiltheinterrupt-*ismapped-*/-staticintxilinx_intc_typetable[XILINX_INTC_MAXIRQS];--/* Map the interrupt type from the device tree to the interrupt types-*usedbytheinterruptsubsystem-*/-staticunsignedcharxilinx_intc_map_senses[]={-IRQ_TYPE_EDGE_RISING,-IRQ_TYPE_EDGE_FALLING,-IRQ_TYPE_LEVEL_HIGH,-IRQ_TYPE_LEVEL_LOW,-};--/*-*Theinterruptcontrollerissetupsuchthatitdoesn'tworkwellwith-*thelevelinterrupthandlerinthekernelbecausethehandleracksthe-*interruptbeforecallingtheapplicationinterrupthandler.Todealwith-*that,weuse2differentirqchipssothatdifferentfunctionscanbe-*usedforlevelandedgetypeinterrupts.-*-*IRQChipcommon(acrosslevelandedge)operations-*/-staticvoidxilinx_intc_mask(structirq_data*d)-{-intirq=irqd_to_hwirq(d);-void*regs=irq_data_get_irq_chip_data(d);-pr_debug("mask: %d\n",irq);-out_be32(regs+XINTC_CIE,1<<irq);-}--staticintxilinx_intc_set_type(structirq_data*d,unsignedintflow_type)-{-return0;-}--/*-*IRQChipleveloperations-*/-staticvoidxilinx_intc_level_unmask(structirq_data*d)-{-intirq=irqd_to_hwirq(d);-void*regs=irq_data_get_irq_chip_data(d);-pr_debug("unmask: %d\n",irq);-out_be32(regs+XINTC_SIE,1<<irq);--/* ack level irqs because they can't be acked during-*ackfunctionsincethehandle_level_irqfunction-*ackstheirqbeforecallingtheinerrupthandler-*/-out_be32(regs+XINTC_IAR,1<<irq);-}--staticstructirq_chipxilinx_intc_level_irqchip={-.name="Xilinx Level INTC",-.irq_mask=xilinx_intc_mask,-.irq_mask_ack=xilinx_intc_mask,-.irq_unmask=xilinx_intc_level_unmask,-.irq_set_type=xilinx_intc_set_type,-};--/*-*IRQChipedgeoperations-*/-staticvoidxilinx_intc_edge_unmask(structirq_data*d)-{-intirq=irqd_to_hwirq(d);-void*regs=irq_data_get_irq_chip_data(d);-pr_debug("unmask: %d\n",irq);-out_be32(regs+XINTC_SIE,1<<irq);-}--staticvoidxilinx_intc_edge_ack(structirq_data*d)-{-intirq=irqd_to_hwirq(d);-void*regs=irq_data_get_irq_chip_data(d);-pr_debug("ack: %d\n",irq);-out_be32(regs+XINTC_IAR,1<<irq);-}--staticstructirq_chipxilinx_intc_edge_irqchip={-.name="Xilinx Edge INTC",-.irq_mask=xilinx_intc_mask,-.irq_unmask=xilinx_intc_edge_unmask,-.irq_ack=xilinx_intc_edge_ack,-.irq_set_type=xilinx_intc_set_type,-};--/*-*IRQHostoperations-*/--/**-*xilinx_intc_xlate-translatevirq#fromdevicetreeinterruptsproperty-*/-staticintxilinx_intc_xlate(structirq_domain*h,structdevice_node*ct,-constu32*intspec,unsignedintintsize,-irq_hw_number_t*out_hwirq,-unsignedint*out_flags)-{-if((intsize<2)||(intspec[0]>=XILINX_INTC_MAXIRQS))-return-EINVAL;--/* keep a copy of the interrupt type til the interrupt is mapped-*/-xilinx_intc_typetable[intspec[0]]=xilinx_intc_map_senses[intspec[1]];--/* Xilinx uses 2 interrupt entries, the 1st being the h/w-*interruptnumber,the2ndbeingtheinterrupttype,edgeorlevel-*/-*out_hwirq=intspec[0];-*out_flags=xilinx_intc_map_senses[intspec[1]];--return0;-}-staticintxilinx_intc_map(structirq_domain*h,unsignedintvirq,-irq_hw_number_tirq)-{-irq_set_chip_data(virq,h->host_data);--if(xilinx_intc_typetable[irq]==IRQ_TYPE_LEVEL_HIGH||-xilinx_intc_typetable[irq]==IRQ_TYPE_LEVEL_LOW){-irq_set_chip_and_handler(virq,&xilinx_intc_level_irqchip,-handle_level_irq);-}else{-irq_set_chip_and_handler(virq,&xilinx_intc_edge_irqchip,-handle_edge_irq);-}-return0;-}--staticconststructirq_domain_opsxilinx_intc_ops={-.map=xilinx_intc_map,-.xlate=xilinx_intc_xlate,-};--structirq_domain*__init-xilinx_intc_init(structdevice_node*np)-{-structirq_domain*irq;-void*regs;--/* Find and map the intc registers */-regs=of_iomap(np,0);-if(!regs){-pr_err("xilinx_intc: could not map registers\n");-returnNULL;-}--/* Setup interrupt controller */-out_be32(regs+XINTC_IER,0);/* disable all irqs */-out_be32(regs+XINTC_IAR,~(u32)0);/* Acknowledge pending irqs */-out_be32(regs+XINTC_MER,0x3UL);/* Turn on the Master Enable. */--/* Allocate and initialize an irq_domain structure. */-irq=irq_domain_add_linear(np,XILINX_INTC_MAXIRQS,&xilinx_intc_ops,-regs);-if(!irq)-panic(__FILE__": Cannot allocate IRQ host\n");--returnirq;-}--intxilinx_intc_get_irq(void)-{-void*regs=master_irqhost->host_data;-pr_debug("get_irq:\n");-returnirq_linear_revmap(master_irqhost,in_be32(regs+XINTC_IVR));-}+#include<linux/irqchip.h>#if defined(CONFIG_PPC_I8259)/*
From: Michal Simek <hidden> Date: 2016-11-15 13:59:17
On 14.11.2016 13:13, Zubair Lutfullah Kakakhel wrote:
quoted hunk
The powerpc dts file does not have the xlnx,kind-of-intr property.
Instead of erroring out, give a warning instead. And attempt to
continue to probe the interrupt controller while assuming
kind-of-intr is 0x0 as a fall back.
Signed-off-by: Zubair Lutfullah Kakakhel <redacted>
---
V6 -> V7
Rebase to v4.9-rc5
V5 -> V6
Rebase to v4.9-rc3
V5 new patch
---
drivers/irqchip/irq-xilinx-intc.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
From: Michal Simek <hidden> Date: 2016-11-15 14:00:21
On 14.11.2016 13:13, Zubair Lutfullah Kakakhel wrote:
quoted hunk
Now that the driver is generic and used by multiple archs,
get_irq is too generic.
Rename get_irq to xintc_get_irq to avoid any conflicts
Signed-off-by: Zubair Lutfullah Kakakhel <redacted>
---
V6 -> V7
Rebase to v4.9-rc5
V5 -> V6
Removed __func__ in printk
Rebase to v4.9-rc3
V4 -> V5
Rebased to v4.9-rc1
Use __func__ in pr_err
V3 -> V4
New patch.
---
arch/microblaze/include/asm/irq.h | 2 +-
arch/microblaze/kernel/irq.c | 4 ++--
drivers/irqchip/irq-xilinx-intc.c | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
@@ -16,6 +16,6 @@ struct pt_regs;externvoiddo_IRQ(structpt_regs*regs);/* should be defined in each interrupt controller driver */-externunsignedintget_irq(void);+externunsignedintxintc_get_irq(void);#endif /* _ASM_MICROBLAZE_IRQ_H */
On 14.11.2016 13:13, Zubair Lutfullah Kakakhel wrote:
quoted
Add a global structure to house various variables.
And cleanup read/write handling by using jump label api.
Signed-off-by: Zubair Lutfullah Kakakhel <redacted>
I don't agree with this.
Pretty long time ago we were added support for multiple instances in
xilinx private tree.
You can look here.
https://github.com/Xilinx/linux-xlnx/blob/master/drivers/irqchip/irq-xilinx-intc.c
Not sure if this the latest way how to do it but as you can see
we were setting up
irq_set_handler_data(irq, intc);
and then when you need that structure we were calling
struct intc *local_intc = irq_data_get_irq_chip_data(d);
And that should be it to support multiple instance of this driver.
Based on 5/7 you are describing your interrupt subsystem like this.
Peripherals --> xilinx_intcontroller -> mips_cpu_int controller
If mips_cpu_int has more than one input you can connect more xilinx intc
controllers.
If not you still have an option to connect
xilinx_intcontroller(up to 32 peripherals) -> xilinx_intcontroller(one
intc + up to 31 peripherals) -> mips_cpu_int controller
That configuration in FPGA is technically possible. Although not done/needed in the
way we use the Xilinx Interrupt Controller IP block in MIPSfpga.
This series takes the drivers out of arch code and makes it accessible.
Any further development on the driver would be common to all architectures.
Support for multiple instances would be a 'new feature'.
I say this as this series keeps growing and mutating in terms of its scope
and work.
Would it be possible to ack this so that the restructure out of arch code
can move forward?
Regards,
ZubairLK
From: Michal Simek <hidden> Date: 2016-11-16 09:25:23
On 15.11.2016 17:03, Zubair Lutfullah Kakakhel wrote:
Hi,
On 11/15/2016 12:49 PM, Michal Simek wrote:
quoted
On 14.11.2016 13:13, Zubair Lutfullah Kakakhel wrote:
quoted
Add a global structure to house various variables.
And cleanup read/write handling by using jump label api.
Signed-off-by: Zubair Lutfullah Kakakhel <redacted>
I don't agree with this.
Pretty long time ago we were added support for multiple instances in
xilinx private tree.
You can look here.
https://github.com/Xilinx/linux-xlnx/blob/master/drivers/irqchip/irq-xilinx-intc.c
Not sure if this the latest way how to do it but as you can see
we were setting up
irq_set_handler_data(irq, intc);
and then when you need that structure we were calling
struct intc *local_intc = irq_data_get_irq_chip_data(d);
And that should be it to support multiple instance of this driver.
Based on 5/7 you are describing your interrupt subsystem like this.
Peripherals --> xilinx_intcontroller -> mips_cpu_int controller
If mips_cpu_int has more than one input you can connect more xilinx intc
controllers.
If not you still have an option to connect
xilinx_intcontroller(up to 32 peripherals) -> xilinx_intcontroller(one
intc + up to 31 peripherals) -> mips_cpu_int controller
That configuration in FPGA is technically possible. Although not
done/needed in the
way we use the Xilinx Interrupt Controller IP block in MIPSfpga.
This series takes the drivers out of arch code and makes it accessible.
Any further development on the driver would be common to all architectures.
Support for multiple instances would be a 'new feature'.
I say this as this series keeps growing and mutating in terms of its scope
and work.
fair enough - it can be added in separate patch.
Would it be possible to ack this so that the restructure out of arch code
can move forward?
I have tested the whole series on Microblaze and I can't see any problem
in running it there.
That's why
Tested-by; Michal Simek [off-list ref]
If everything is right needs to be checked by irqchip experts.
Thanks,
Michal
From: Thomas Gleixner <hidden> Date: 2016-11-18 13:32:33
On Mon, 14 Nov 2016, Zubair Lutfullah Kakakhel wrote:
The powerpc dts file does not have the xlnx,kind-of-intr property.
Instead of erroring out, give a warning instead. And attempt to
continue to probe the interrupt controller while assuming
kind-of-intr is 0x0 as a fall back.
This is broken, really. On multiplatform kernels this will try to probe the
chip no matter what.
Powerpc already has:
static const struct of_device_id xilinx_intc_match[] __initconst = {
{ .compatible = "xlnx,opb-intc-1.00.c", },
{ .compatible = "xlnx,xps-intc-1.00.a", },
{}
};
Unless I'm missing something important, then adding those compatible
strings to the driver will just keep stuff working as expected instead of
adding unsafe and broken heuristics.
Thanks,
tglx
Hi,
On 11/18/2016 01:29 PM, Thomas Gleixner wrote:
On Mon, 14 Nov 2016, Zubair Lutfullah Kakakhel wrote:
quoted
The powerpc dts file does not have the xlnx,kind-of-intr property.
Instead of erroring out, give a warning instead. And attempt to
continue to probe the interrupt controller while assuming
kind-of-intr is 0x0 as a fall back.
This is broken, really. On multiplatform kernels this will try to probe the
chip no matter what.
I'm not sure I understand why this driver will probe on multi-platform kernels
if the compatible string isn't in the DT?
Powerpc already has:
static const struct of_device_id xilinx_intc_match[] __initconst = {
{ .compatible = "xlnx,opb-intc-1.00.c", },
{ .compatible = "xlnx,xps-intc-1.00.a", },
{}
};
Unless I'm missing something important, then adding those compatible
strings to the driver will just keep stuff working as expected instead of
adding unsafe and broken heuristics.
The last two lines of the driver already specify the compatible strings.
"
IRQCHIP_DECLARE(xilinx_intc_xps, "xlnx,xps-intc-1.00.a", xilinx_intc_of_init);
IRQCHIP_DECLARE(xilinx_intc_opb, "xlnx,opb-intc-1.00.c", xilinx_intc_of_init);
"
I'll elaborate on the commit message.
The DT node in arch/powerpc for this driver is
intc_0: interrupt-controller@81800000 {
#interrupt-cells = <0x2>;
compatible = "xlnx,xps-intc-1.00.a";
interrupt-controller ;
reg = < 0x81800000 0x10000 >;
xlnx,num-intr-inputs = <0xc>;
} ;
The DT node in arch/microblaze for this driver is
intc_0: interrupt-controller@81800000 {
#interrupt-cells = <0x2>;
compatible = "xlnx,xps-intc-1.00.a";
interrupt-controller ;
reg = < 0x81800000 0x10000 >;
xlnx,kind-of-intr = <0x100>; //<Missing from ppc>!
xlnx,num-intr-inputs = <0x9>;
} ;
The PPC driver assumes the kind-of-intr value be 0x0 and doesn't specify it in DT.
This patch makes that a fall back case. Instead of completely error-ing out.
Regards,
ZubairLK
From: Marc Zyngier <hidden> Date: 2016-11-21 14:17:31
On 21/11/16 14:05, Zubair Lutfullah Kakakhel wrote:
Hi,
On 11/18/2016 01:29 PM, Thomas Gleixner wrote:
quoted
On Mon, 14 Nov 2016, Zubair Lutfullah Kakakhel wrote:
quoted
The powerpc dts file does not have the xlnx,kind-of-intr property.
Instead of erroring out, give a warning instead. And attempt to
continue to probe the interrupt controller while assuming
kind-of-intr is 0x0 as a fall back.
This is broken, really. On multiplatform kernels this will try to probe the
chip no matter what.
I'm not sure I understand why this driver will probe on multi-platform kernels
if the compatible string isn't in the DT?
quoted
Powerpc already has:
static const struct of_device_id xilinx_intc_match[] __initconst = {
{ .compatible = "xlnx,opb-intc-1.00.c", },
{ .compatible = "xlnx,xps-intc-1.00.a", },
{}
};
Unless I'm missing something important, then adding those compatible
strings to the driver will just keep stuff working as expected instead of
adding unsafe and broken heuristics.
The last two lines of the driver already specify the compatible strings.
"
IRQCHIP_DECLARE(xilinx_intc_xps, "xlnx,xps-intc-1.00.a", xilinx_intc_of_init);
IRQCHIP_DECLARE(xilinx_intc_opb, "xlnx,opb-intc-1.00.c", xilinx_intc_of_init);
"
Is PPC actually using this infrastructure? It predates the whole
IRQCHIP_DECLARE business by about a decade. You seem to have tested it
using QEMU, so I assume it "just works", but I'd feel more reassured it
you stated so...
Thanks,
M.
--
Jazz is not dead. It just smells funny...
On 21/11/16 14:05, Zubair Lutfullah Kakakhel wrote:
quoted
Hi,
On 11/18/2016 01:29 PM, Thomas Gleixner wrote:
quoted
On Mon, 14 Nov 2016, Zubair Lutfullah Kakakhel wrote:
quoted
The powerpc dts file does not have the xlnx,kind-of-intr property.
Instead of erroring out, give a warning instead. And attempt to
continue to probe the interrupt controller while assuming
kind-of-intr is 0x0 as a fall back.
This is broken, really. On multiplatform kernels this will try to probe the
chip no matter what.
I'm not sure I understand why this driver will probe on multi-platform kernels
if the compatible string isn't in the DT?
quoted
Powerpc already has:
static const struct of_device_id xilinx_intc_match[] __initconst = {
{ .compatible = "xlnx,opb-intc-1.00.c", },
{ .compatible = "xlnx,xps-intc-1.00.a", },
{}
};
Unless I'm missing something important, then adding those compatible
strings to the driver will just keep stuff working as expected instead of
adding unsafe and broken heuristics.
The last two lines of the driver already specify the compatible strings.
"
IRQCHIP_DECLARE(xilinx_intc_xps, "xlnx,xps-intc-1.00.a", xilinx_intc_of_init);
IRQCHIP_DECLARE(xilinx_intc_opb, "xlnx,opb-intc-1.00.c", xilinx_intc_of_init);
"
Is PPC actually using this infrastructure? It predates the whole
IRQCHIP_DECLARE business by about a decade. You seem to have tested it
using QEMU, so I assume it "just works", but I'd feel more reassured it
you stated so...
I didn't realize that it could have been an issue.
I simply included <linux/irqchip.h> and called irqchip_init() in the platform code
instead of the previous initialization. Patch 7/7 in this series does that.
And yes I tested it on QEMU. And it does look like it 'just works'.
Without this patch, the UART driver would revert to polling and there would be various
error messages about no irq domain found. With this patch, the 'no irq domain found'
messages disappeared and the uart driver did get an irq.
Regards,
ZubairLK
From: Thomas Gleixner <hidden> Date: 2016-11-21 15:51:09
On Mon, 21 Nov 2016, Zubair Lutfullah Kakakhel wrote:
On 11/18/2016 01:29 PM, Thomas Gleixner wrote:
I'll elaborate on the commit message.
The DT node in arch/powerpc for this driver is
intc_0: interrupt-controller@81800000 {
#interrupt-cells = <0x2>;
compatible = "xlnx,xps-intc-1.00.a";
interrupt-controller ;
reg = < 0x81800000 0x10000 >;
xlnx,num-intr-inputs = <0xc>;
} ;
The DT node in arch/microblaze for this driver is
intc_0: interrupt-controller@81800000 {
#interrupt-cells = <0x2>;
compatible = "xlnx,xps-intc-1.00.a";
interrupt-controller ;
reg = < 0x81800000 0x10000 >;
xlnx,kind-of-intr = <0x100>; //<Missing from ppc>!
xlnx,num-intr-inputs = <0x9>;
} ;
The PPC driver assumes the kind-of-intr value be 0x0 and doesn't specify it in
DT.
This patch makes that a fall back case. Instead of completely error-ing out.
Ok. makes sense. I misread the changelog/patch.
Thanks,
tglx
From: Marc Zyngier <hidden> Date: 2016-11-22 10:55:26
On 14/11/16 12:13, Zubair Lutfullah Kakakhel wrote:
Hi,
This patch series moves the Xilinx interrupt controller driver out
of arch/microblaze to drivers/irqchip and then cleans it up a bit.
And then removes another implementation of the driver in arch/powerpc.
This effort results in one common driver usable by mips,microblaze
and powerpc.
Compile tested on microblaze-el.
Tested using qemu-system-ppc using virtix440-ml507
Tested on MIPSfpga platform.
Based on v4.9-rc5
I've queued this for 4.10 with Michal's Acks and TBs.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
On 14/11/16 12:13, Zubair Lutfullah Kakakhel wrote:
quoted
Hi,
This patch series moves the Xilinx interrupt controller driver out
of arch/microblaze to drivers/irqchip and then cleans it up a bit.
And then removes another implementation of the driver in arch/powerpc.
This effort results in one common driver usable by mips,microblaze
and powerpc.
Compile tested on microblaze-el.
Tested using qemu-system-ppc using virtix440-ml507
Tested on MIPSfpga platform.
Based on v4.9-rc5
I've queued this for 4.10 with Michal's Acks and TBs.