diff mbox

[v7,1/4] irqchip: gic: Support hierarchy irq domain.

Message ID 1416406451-4578-2-git-send-email-yingjoe.chen@mediatek.com (mailing list archive)
State New, archived
Headers show

Commit Message

Yingjoe Chen Nov. 19, 2014, 2:14 p.m. UTC
Add support to use gic as a parent for stacked irq domain.

Signed-off-by: Yingjoe Chen <yingjoe.chen@mediatek.com>
---
 drivers/irqchip/Kconfig   |  1 +
 drivers/irqchip/irq-gic.c | 78 ++++++++++++++++++++++++++++++++---------------
 2 files changed, 55 insertions(+), 24 deletions(-)

Comments

Marc Zyngier Nov. 19, 2014, 5:18 p.m. UTC | #1
Hi Yingjoe,

On Wed, Nov 19 2014 at  2:14:08 pm GMT, Yingjoe Chen <yingjoe.chen@mediatek.com> wrote:
> Add support to use gic as a parent for stacked irq domain.
>
> Signed-off-by: Yingjoe Chen <yingjoe.chen@mediatek.com>
> ---
>  drivers/irqchip/Kconfig   |  1 +
>  drivers/irqchip/irq-gic.c | 78 ++++++++++++++++++++++++++++++++---------------
>  2 files changed, 55 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index b21f12f..7f34138 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -5,6 +5,7 @@ config IRQCHIP
>  config ARM_GIC
>  	bool
>  	select IRQ_DOMAIN
> +	select IRQ_DOMAIN_HIERARCHY
>  	select MULTI_IRQ_HANDLER
>  
>  config GIC_NON_BANKED
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index 38493ff..464dd53 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -788,17 +788,16 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
>  {
>  	if (hw < 32) {
>  		irq_set_percpu_devid(irq);
> -		irq_set_chip_and_handler(irq, &gic_chip,
> -					 handle_percpu_devid_irq);
> +		irq_domain_set_info(d, irq, hw, &gic_chip, d->host_data,
> +				    handle_percpu_devid_irq, NULL, NULL);
>  		set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
>  	} else {
> -		irq_set_chip_and_handler(irq, &gic_chip,
> -					 handle_fasteoi_irq);
> +		irq_domain_set_info(d, irq, hw, &gic_chip, d->host_data,
> +				    handle_fasteoi_irq, NULL, NULL);
>  		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
>  
>  		gic_routable_irq_domain_ops->map(d, irq, hw);
>  	}
> -	irq_set_chip_data(irq, d->host_data);
>  	return 0;
>  }
>  
> @@ -858,6 +857,31 @@ static struct notifier_block gic_cpu_notifier = {
>  };
>  #endif
>  
> +static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
> +				unsigned int nr_irqs, void *arg)
> +{
> +	int i, ret;
> +	irq_hw_number_t hwirq;
> +	unsigned int type = IRQ_TYPE_NONE;
> +	struct of_phandle_args *irq_data = arg;
> +
> +	ret = gic_irq_domain_xlate(domain, irq_data->np, irq_data->args,
> +				   irq_data->args_count, &hwirq, &type);
> +	if (ret)
> +		return ret;
> +
> +	for (i = 0; i < nr_irqs; i++)
> +		gic_irq_domain_map(domain, virq+i, hwirq+i);

nit: spacing around '+'.

> +
> +	return 0;
> +}
> +
> +static const struct irq_domain_ops gic_irq_domain_hierarchy_ops = {
> +	.xlate = gic_irq_domain_xlate,
> +	.alloc = gic_irq_domain_alloc,
> +	.free = irq_domain_free_irqs_top,

I'm convinced that irq_domain_free_irqs_top is the wrong function to
call here, because you're calling it from the bottom, not the top-level
(it has no parent).

I cannot verify this with your code as I don't a working platform with
GICv2m, but if I enable something similar on GICv3, it dies a very
painful way:

Unable to handle kernel NULL pointer dereference at virtual address 00000018
pgd = ffffffc03d059000
[00000018] *pgd=0000000081356003, *pud=0000000081356003, *pmd=0000000000000000
Internal error: Oops: 96000006 [#1] SMP
Modules linked in:
CPU: 4 PID: 1052 Comm: sh Not tainted 3.18.0-rc4+ #3311
task: ffffffc03e320000 ti: ffffffc001390000 task.ti: ffffffc001390000
PC is at irq_domain_free_irqs_recursive+0x1c/0x80
LR is at irq_domain_free_irqs_common+0x88/0x9c
pc : [<ffffffc0000ed790>] lr : [<ffffffc0000ede20>] pstate: 60000145
[...]
[<ffffffc0000ed790>] irq_domain_free_irqs_recursive+0x1c/0x80
[<ffffffc0000ede1c>] irq_domain_free_irqs_common+0x84/0x9c
[<ffffffc0000ede98>] irq_domain_free_irqs_top+0x64/0x7c  <-- gic_domain.free()
[<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
[<ffffffc0000ee468>] irq_domain_free_irqs_parent+0x14/0x20
[<ffffffc0003500b8>] its_irq_domain_free+0xc8/0x250
[<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
[<ffffffc0000ede1c>] irq_domain_free_irqs_common+0x84/0x9c
[<ffffffc0000ede98>] irq_domain_free_irqs_top+0x64/0x7c
[<ffffffc0000ef518>] msi_domain_free+0x70/0x88
[<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
[<ffffffc0000ee3ac>] irq_domain_free_irqs+0x108/0x17c
[<ffffffc0000efb68>] msi_domain_free_irqs+0x28/0x4c
[<ffffffc000369cac>] free_msi_irqs+0xb4/0x1c0
[<ffffffc00036adec>] pci_disable_msix+0x3c/0x4c
[...]

and I cannot see how this could work on the standard GIC either.

Thomas, Jiang: could you please confirm or infirm my suspicions? My
understanding is that irq_domain_free_irqs_top can only be called from
the top-level domain.

> +};
> +
>  static const struct irq_domain_ops gic_irq_domain_ops = {
>  	.map = gic_irq_domain_map,
>  	.unmap = gic_irq_domain_unmap,
> @@ -948,18 +972,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>  		gic_cpu_map[i] = 0xff;
>  
>  	/*
> -	 * For primary GICs, skip over SGIs.
> -	 * For secondary GICs, skip over PPIs, too.
> -	 */
> -	if (gic_nr == 0 && (irq_start & 31) > 0) {
> -		hwirq_base = 16;
> -		if (irq_start != -1)
> -			irq_start = (irq_start & ~31) + 16;
> -	} else {
> -		hwirq_base = 32;
> -	}
> -
> -	/*
>  	 * Find out how many interrupts are supported.
>  	 * The GIC only supports up to 1020 interrupt sources.
>  	 */
> @@ -969,10 +981,32 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>  		gic_irqs = 1020;
>  	gic->gic_irqs = gic_irqs;
>  
> -	gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
> +	if (node) {		/* DT case */
> +		const struct irq_domain_ops *ops =
> +					&gic_irq_domain_hierarchy_ops;

nit: please put this on the same line, even if it is longer than 80
characters.

> +
> +		if (!of_property_read_u32(node, "arm,routable-irqs",
> +					  &nr_routable_irqs)) {
> +			ops = &gic_irq_domain_ops;
> +			gic_irqs = nr_routable_irqs;
> +		}
> +
> +		gic->domain = irq_domain_add_linear(node, gic_irqs, ops, gic);
> +	} else {		/* Non-DT case */
> +		/*
> +		 * For primary GICs, skip over SGIs.
> +		 * For secondary GICs, skip over PPIs, too.
> +		 */
> +		if (gic_nr == 0 && (irq_start & 31) > 0) {
> +			hwirq_base = 16;
> +			if (irq_start != -1)
> +				irq_start = (irq_start & ~31) + 16;
> +		} else {
> +			hwirq_base = 32;
> +		}
> +
> +		gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
>  
> -	if (of_property_read_u32(node, "arm,routable-irqs",
> -				 &nr_routable_irqs)) {
>  		irq_base = irq_alloc_descs(irq_start, 16, gic_irqs,
>  					   numa_node_id());
>  		if (IS_ERR_VALUE(irq_base)) {
> @@ -983,10 +1017,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>  
>  		gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
>  					hwirq_base, &gic_irq_domain_ops, gic);
> -	} else {
> -		gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
> -						    &gic_irq_domain_ops,
> -						    gic);
>  	}
>  
>  	if (WARN_ON(!gic->domain))

Thanks,

	M.
Yingjoe Chen Nov. 20, 2014, 3:57 a.m. UTC | #2
Hi Marc,

On Wed, 2014-11-19 at 17:18 +0000, Marc Zyngier wrote:
> > +static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
> > +				unsigned int nr_irqs, void *arg)
> > +{
> > +	int i, ret;
> > +	irq_hw_number_t hwirq;
> > +	unsigned int type = IRQ_TYPE_NONE;
> > +	struct of_phandle_args *irq_data = arg;
> > +
> > +	ret = gic_irq_domain_xlate(domain, irq_data->np, irq_data->args,
> > +				   irq_data->args_count, &hwirq, &type);
> > +	if (ret)
> > +		return ret;
> > +
> > +	for (i = 0; i < nr_irqs; i++)
> > +		gic_irq_domain_map(domain, virq+i, hwirq+i);
> 
> nit: spacing around '+'.

OK.

> > +
> > +	return 0;
> > +}
> > +
> > +static const struct irq_domain_ops gic_irq_domain_hierarchy_ops = {
> > +	.xlate = gic_irq_domain_xlate,
> > +	.alloc = gic_irq_domain_alloc,
> > +	.free = irq_domain_free_irqs_top,
> 
> I'm convinced that irq_domain_free_irqs_top is the wrong function to
> call here, because you're calling it from the bottom, not the top-level
> (it has no parent).

Base on the name, I though this is helper function for top level
irq_domain?

> I cannot verify this with your code as I don't a working platform with
> GICv2m, but if I enable something similar on GICv3, it dies a very
> painful way:
> 
> Unable to handle kernel NULL pointer dereference at virtual address 00000018
> pgd = ffffffc03d059000
> [00000018] *pgd=0000000081356003, *pud=0000000081356003, *pmd=0000000000000000
> Internal error: Oops: 96000006 [#1] SMP
> Modules linked in:
> CPU: 4 PID: 1052 Comm: sh Not tainted 3.18.0-rc4+ #3311
> task: ffffffc03e320000 ti: ffffffc001390000 task.ti: ffffffc001390000
> PC is at irq_domain_free_irqs_recursive+0x1c/0x80
> LR is at irq_domain_free_irqs_common+0x88/0x9c
> pc : [<ffffffc0000ed790>] lr : [<ffffffc0000ede20>] pstate: 60000145
> [...]
> [<ffffffc0000ed790>] irq_domain_free_irqs_recursive+0x1c/0x80
> [<ffffffc0000ede1c>] irq_domain_free_irqs_common+0x84/0x9c
> [<ffffffc0000ede98>] irq_domain_free_irqs_top+0x64/0x7c  <-- gic_domain.free()
> [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
> [<ffffffc0000ee468>] irq_domain_free_irqs_parent+0x14/0x20
> [<ffffffc0003500b8>] its_irq_domain_free+0xc8/0x250
> [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
> [<ffffffc0000ede1c>] irq_domain_free_irqs_common+0x84/0x9c
> [<ffffffc0000ede98>] irq_domain_free_irqs_top+0x64/0x7c
> [<ffffffc0000ef518>] msi_domain_free+0x70/0x88
> [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
> [<ffffffc0000ee3ac>] irq_domain_free_irqs+0x108/0x17c
> [<ffffffc0000efb68>] msi_domain_free_irqs+0x28/0x4c
> [<ffffffc000369cac>] free_msi_irqs+0xb4/0x1c0
> [<ffffffc00036adec>] pci_disable_msix+0x3c/0x4c
> [...]
> 
> and I cannot see how this could work on the standard GIC either.

I'm sorry, I just realize my testcase was too simple, irqs are populated
by device tree and never got freed. I'll add that and test it again.

> Thomas, Jiang: could you please confirm or infirm my suspicions? My
> understanding is that irq_domain_free_irqs_top can only be called from
> the top-level domain.
> 
> > +};
> > +
> >  static const struct irq_domain_ops gic_irq_domain_ops = {
> >  	.map = gic_irq_domain_map,
> >  	.unmap = gic_irq_domain_unmap,
> > @@ -948,18 +972,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
> >  		gic_cpu_map[i] = 0xff;
> >  
> >  	/*
> > -	 * For primary GICs, skip over SGIs.
> > -	 * For secondary GICs, skip over PPIs, too.
> > -	 */
> > -	if (gic_nr == 0 && (irq_start & 31) > 0) {
> > -		hwirq_base = 16;
> > -		if (irq_start != -1)
> > -			irq_start = (irq_start & ~31) + 16;
> > -	} else {
> > -		hwirq_base = 32;
> > -	}
> > -
> > -	/*
> >  	 * Find out how many interrupts are supported.
> >  	 * The GIC only supports up to 1020 interrupt sources.
> >  	 */
> > @@ -969,10 +981,32 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
> >  		gic_irqs = 1020;
> >  	gic->gic_irqs = gic_irqs;
> >  
> > -	gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
> > +	if (node) {		/* DT case */
> > +		const struct irq_domain_ops *ops =
> > +					&gic_irq_domain_hierarchy_ops;
> 
> nit: please put this on the same line, even if it is longer than 80
> characters.

ok.

Joe.C
Jiang Liu Nov. 20, 2014, 4:26 a.m. UTC | #3
On 2014/11/20 1:18, Marc Zyngier wrote:
> Hi Yingjoe,
> 
> On Wed, Nov 19 2014 at  2:14:08 pm GMT, Yingjoe Chen <yingjoe.chen@mediatek.com> wrote:
>> Add support to use gic as a parent for stacked irq domain.
>>
>> Signed-off-by: Yingjoe Chen <yingjoe.chen@mediatek.com>
>> ---
>>  drivers/irqchip/Kconfig   |  1 +
>>  drivers/irqchip/irq-gic.c | 78 ++++++++++++++++++++++++++++++++---------------
>>  2 files changed, 55 insertions(+), 24 deletions(-)
>>
>> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
>> index b21f12f..7f34138 100644
>> --- a/drivers/irqchip/Kconfig
>> +++ b/drivers/irqchip/Kconfig
>> @@ -5,6 +5,7 @@ config IRQCHIP
>>  config ARM_GIC
>>  	bool
>>  	select IRQ_DOMAIN
>> +	select IRQ_DOMAIN_HIERARCHY
>>  	select MULTI_IRQ_HANDLER
>>  
>>  config GIC_NON_BANKED
>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>> index 38493ff..464dd53 100644
>> --- a/drivers/irqchip/irq-gic.c
>> +++ b/drivers/irqchip/irq-gic.c
>> @@ -788,17 +788,16 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
>>  {
>>  	if (hw < 32) {
>>  		irq_set_percpu_devid(irq);
>> -		irq_set_chip_and_handler(irq, &gic_chip,
>> -					 handle_percpu_devid_irq);
>> +		irq_domain_set_info(d, irq, hw, &gic_chip, d->host_data,
>> +				    handle_percpu_devid_irq, NULL, NULL);
>>  		set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
>>  	} else {
>> -		irq_set_chip_and_handler(irq, &gic_chip,
>> -					 handle_fasteoi_irq);
>> +		irq_domain_set_info(d, irq, hw, &gic_chip, d->host_data,
>> +				    handle_fasteoi_irq, NULL, NULL);
>>  		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
>>  
>>  		gic_routable_irq_domain_ops->map(d, irq, hw);
>>  	}
>> -	irq_set_chip_data(irq, d->host_data);
>>  	return 0;
>>  }
>>  
>> @@ -858,6 +857,31 @@ static struct notifier_block gic_cpu_notifier = {
>>  };
>>  #endif
>>  
>> +static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
>> +				unsigned int nr_irqs, void *arg)
>> +{
>> +	int i, ret;
>> +	irq_hw_number_t hwirq;
>> +	unsigned int type = IRQ_TYPE_NONE;
>> +	struct of_phandle_args *irq_data = arg;
>> +
>> +	ret = gic_irq_domain_xlate(domain, irq_data->np, irq_data->args,
>> +				   irq_data->args_count, &hwirq, &type);
>> +	if (ret)
>> +		return ret;
>> +
>> +	for (i = 0; i < nr_irqs; i++)
>> +		gic_irq_domain_map(domain, virq+i, hwirq+i);
> 
> nit: spacing around '+'.
> 
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct irq_domain_ops gic_irq_domain_hierarchy_ops = {
>> +	.xlate = gic_irq_domain_xlate,
>> +	.alloc = gic_irq_domain_alloc,
>> +	.free = irq_domain_free_irqs_top,
> 
> I'm convinced that irq_domain_free_irqs_top is the wrong function to
> call here, because you're calling it from the bottom, not the top-level
> (it has no parent).
> 
> I cannot verify this with your code as I don't a working platform with
> GICv2m, but if I enable something similar on GICv3, it dies a very
> painful way:
> 
> Unable to handle kernel NULL pointer dereference at virtual address 00000018
> pgd = ffffffc03d059000
> [00000018] *pgd=0000000081356003, *pud=0000000081356003, *pmd=0000000000000000
> Internal error: Oops: 96000006 [#1] SMP
> Modules linked in:
> CPU: 4 PID: 1052 Comm: sh Not tainted 3.18.0-rc4+ #3311
> task: ffffffc03e320000 ti: ffffffc001390000 task.ti: ffffffc001390000
> PC is at irq_domain_free_irqs_recursive+0x1c/0x80
> LR is at irq_domain_free_irqs_common+0x88/0x9c
> pc : [<ffffffc0000ed790>] lr : [<ffffffc0000ede20>] pstate: 60000145
> [...]
> [<ffffffc0000ed790>] irq_domain_free_irqs_recursive+0x1c/0x80
> [<ffffffc0000ede1c>] irq_domain_free_irqs_common+0x84/0x9c
> [<ffffffc0000ede98>] irq_domain_free_irqs_top+0x64/0x7c  <-- gic_domain.free()
> [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
> [<ffffffc0000ee468>] irq_domain_free_irqs_parent+0x14/0x20
> [<ffffffc0003500b8>] its_irq_domain_free+0xc8/0x250
> [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
> [<ffffffc0000ede1c>] irq_domain_free_irqs_common+0x84/0x9c
> [<ffffffc0000ede98>] irq_domain_free_irqs_top+0x64/0x7c
> [<ffffffc0000ef518>] msi_domain_free+0x70/0x88
> [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
> [<ffffffc0000ee3ac>] irq_domain_free_irqs+0x108/0x17c
> [<ffffffc0000efb68>] msi_domain_free_irqs+0x28/0x4c
> [<ffffffc000369cac>] free_msi_irqs+0xb4/0x1c0
> [<ffffffc00036adec>] pci_disable_msix+0x3c/0x4c
> [...]
> 
> and I cannot see how this could work on the standard GIC either.
> 
> Thomas, Jiang: could you please confirm or infirm my suspicions? My
> understanding is that irq_domain_free_irqs_top can only be called from
> the top-level domain.
Hi Marc,
	It indicates that irq_domain_free_irqs_top() is not a good name.
We have:
1) irq_domain_set_hwirq_and_chip() to set irq_chip and chip_data
2) irq_domain_set_info() to set irq_chip, chip_data, flow_handler and
   handler_data;
3) irq_domain_reset_irq_data() resets irq_chip and chip_data.
4) irq_domain_free_irqs_common() resets irq_chip, chip_data and calls
   parent domain's domain_ops.free() callback.
5) irq_domain_free_irqs_top() resets irq_chip, chip_data, flow handler,
   handler_data and call parent domain's domain_ops.free() callback.

So there two possible improvements here:
1) Rename irq_domain_free_irqs_top() with better name, any suggestions?
   It's named as is because it's always called by the outer-most
   irqdomains on x86.
2) Change irq_domain_free_irqs_common() and irq_domain_free_irqs_top()
   to call parent domain's domain_ops.free() callback only if parent
   exists. By this way, they could be used for inner-most irqdomains.
If OK, I will respin a version 4 patch set based on tip/irq/irqdomain.
Thoughts?
Regards!
Gerry
> 
>> +};
>> +
>>  static const struct irq_domain_ops gic_irq_domain_ops = {
>>  	.map = gic_irq_domain_map,
>>  	.unmap = gic_irq_domain_unmap,
>> @@ -948,18 +972,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>>  		gic_cpu_map[i] = 0xff;
>>  
>>  	/*
>> -	 * For primary GICs, skip over SGIs.
>> -	 * For secondary GICs, skip over PPIs, too.
>> -	 */
>> -	if (gic_nr == 0 && (irq_start & 31) > 0) {
>> -		hwirq_base = 16;
>> -		if (irq_start != -1)
>> -			irq_start = (irq_start & ~31) + 16;
>> -	} else {
>> -		hwirq_base = 32;
>> -	}
>> -
>> -	/*
>>  	 * Find out how many interrupts are supported.
>>  	 * The GIC only supports up to 1020 interrupt sources.
>>  	 */
>> @@ -969,10 +981,32 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>>  		gic_irqs = 1020;
>>  	gic->gic_irqs = gic_irqs;
>>  
>> -	gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
>> +	if (node) {		/* DT case */
>> +		const struct irq_domain_ops *ops =
>> +					&gic_irq_domain_hierarchy_ops;
> 
> nit: please put this on the same line, even if it is longer than 80
> characters.
> 
>> +
>> +		if (!of_property_read_u32(node, "arm,routable-irqs",
>> +					  &nr_routable_irqs)) {
>> +			ops = &gic_irq_domain_ops;
>> +			gic_irqs = nr_routable_irqs;
>> +		}
>> +
>> +		gic->domain = irq_domain_add_linear(node, gic_irqs, ops, gic);
>> +	} else {		/* Non-DT case */
>> +		/*
>> +		 * For primary GICs, skip over SGIs.
>> +		 * For secondary GICs, skip over PPIs, too.
>> +		 */
>> +		if (gic_nr == 0 && (irq_start & 31) > 0) {
>> +			hwirq_base = 16;
>> +			if (irq_start != -1)
>> +				irq_start = (irq_start & ~31) + 16;
>> +		} else {
>> +			hwirq_base = 32;
>> +		}
>> +
>> +		gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
>>  
>> -	if (of_property_read_u32(node, "arm,routable-irqs",
>> -				 &nr_routable_irqs)) {
>>  		irq_base = irq_alloc_descs(irq_start, 16, gic_irqs,
>>  					   numa_node_id());
>>  		if (IS_ERR_VALUE(irq_base)) {
>> @@ -983,10 +1017,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>>  
>>  		gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
>>  					hwirq_base, &gic_irq_domain_ops, gic);
>> -	} else {
>> -		gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
>> -						    &gic_irq_domain_ops,
>> -						    gic);
>>  	}
>>  
>>  	if (WARN_ON(!gic->domain))
> 
> Thanks,
> 
> 	M.
>
Yingjoe Chen Nov. 20, 2014, 9:41 a.m. UTC | #4
Hi Marc,

On Thu, 2014-11-20 at 11:57 +0800, Yingjoe Chen wrote:
> On Wed, 2014-11-19 at 17:18 +0000, Marc Zyngier wrote:
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static const struct irq_domain_ops gic_irq_domain_hierarchy_ops = {
> > > +	.xlate = gic_irq_domain_xlate,
> > > +	.alloc = gic_irq_domain_alloc,
> > > +	.free = irq_domain_free_irqs_top,
> > 
> > I'm convinced that irq_domain_free_irqs_top is the wrong function to
> > call here, because you're calling it from the bottom, not the top-level
> > (it has no parent).
> 
> Base on the name, I though this is helper function for top level
> irq_domain?
> 
> > I cannot verify this with your code as I don't a working platform with
> > GICv2m, but if I enable something similar on GICv3, it dies a very
> > painful way:
> > 
> > Unable to handle kernel NULL pointer dereference at virtual address 00000018
> > pgd = ffffffc03d059000
> > [00000018] *pgd=0000000081356003, *pud=0000000081356003, *pmd=0000000000000000
> > Internal error: Oops: 96000006 [#1] SMP
> > Modules linked in:
> > CPU: 4 PID: 1052 Comm: sh Not tainted 3.18.0-rc4+ #3311
> > task: ffffffc03e320000 ti: ffffffc001390000 task.ti: ffffffc001390000
> > PC is at irq_domain_free_irqs_recursive+0x1c/0x80
> > LR is at irq_domain_free_irqs_common+0x88/0x9c
> > pc : [<ffffffc0000ed790>] lr : [<ffffffc0000ede20>] pstate: 60000145
> > [...]
> > [<ffffffc0000ed790>] irq_domain_free_irqs_recursive+0x1c/0x80
> > [<ffffffc0000ede1c>] irq_domain_free_irqs_common+0x84/0x9c
> > [<ffffffc0000ede98>] irq_domain_free_irqs_top+0x64/0x7c  <-- gic_domain.free()
> > [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
> > [<ffffffc0000ee468>] irq_domain_free_irqs_parent+0x14/0x20
> > [<ffffffc0003500b8>] its_irq_domain_free+0xc8/0x250
> > [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
> > [<ffffffc0000ede1c>] irq_domain_free_irqs_common+0x84/0x9c
> > [<ffffffc0000ede98>] irq_domain_free_irqs_top+0x64/0x7c
> > [<ffffffc0000ef518>] msi_domain_free+0x70/0x88
> > [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
> > [<ffffffc0000ee3ac>] irq_domain_free_irqs+0x108/0x17c
> > [<ffffffc0000efb68>] msi_domain_free_irqs+0x28/0x4c
> > [<ffffffc000369cac>] free_msi_irqs+0xb4/0x1c0
> > [<ffffffc00036adec>] pci_disable_msix+0x3c/0x4c
> > [...]
> > 
> > and I cannot see how this could work on the standard GIC either.
> 
> I'm sorry, I just realize my testcase was too simple, irqs are populated
> by device tree and never got freed. I'll add that and test it again.

On a second thoughts, unlike the MSI cases, gic_irq_domain_hierarchy_ops
is only used when we use DT, so we probably will never use the free
function. Is it OK to remove the free support here?

Joe.C
Marc Zyngier Nov. 20, 2014, 10:07 a.m. UTC | #5
On Thu, Nov 20 2014 at  4:26:10 am GMT, Jiang Liu <jiang.liu@linux.intel.com> wrote:

Hi Jiang,

> On 2014/11/20 1:18, Marc Zyngier wrote:
>> Hi Yingjoe,
>> 
>> On Wed, Nov 19 2014 at 2:14:08 pm GMT, Yingjoe Chen
>> <yingjoe.chen@mediatek.com> wrote:
>>> +
>>> +static const struct irq_domain_ops gic_irq_domain_hierarchy_ops = {
>>> +	.xlate = gic_irq_domain_xlate,
>>> +	.alloc = gic_irq_domain_alloc,
>>> +	.free = irq_domain_free_irqs_top,
>> 
>> I'm convinced that irq_domain_free_irqs_top is the wrong function to
>> call here, because you're calling it from the bottom, not the top-level
>> (it has no parent).
>> 
>> I cannot verify this with your code as I don't a working platform with
>> GICv2m, but if I enable something similar on GICv3, it dies a very
>> painful way:
>> 
>> Unable to handle kernel NULL pointer dereference at virtual address 00000018
>> pgd = ffffffc03d059000
>> [00000018] *pgd=0000000081356003, *pud=0000000081356003, *pmd=0000000000000000
>> Internal error: Oops: 96000006 [#1] SMP
>> Modules linked in:
>> CPU: 4 PID: 1052 Comm: sh Not tainted 3.18.0-rc4+ #3311
>> task: ffffffc03e320000 ti: ffffffc001390000 task.ti: ffffffc001390000
>> PC is at irq_domain_free_irqs_recursive+0x1c/0x80
>> LR is at irq_domain_free_irqs_common+0x88/0x9c
>> pc : [<ffffffc0000ed790>] lr : [<ffffffc0000ede20>] pstate: 60000145
>> [...]
>> [<ffffffc0000ed790>] irq_domain_free_irqs_recursive+0x1c/0x80
>> [<ffffffc0000ede1c>] irq_domain_free_irqs_common+0x84/0x9c
>> [<ffffffc0000ede98>] irq_domain_free_irqs_top+0x64/0x7c  <-- gic_domain.free()
>> [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
>> [<ffffffc0000ee468>] irq_domain_free_irqs_parent+0x14/0x20
>> [<ffffffc0003500b8>] its_irq_domain_free+0xc8/0x250
>> [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
>> [<ffffffc0000ede1c>] irq_domain_free_irqs_common+0x84/0x9c
>> [<ffffffc0000ede98>] irq_domain_free_irqs_top+0x64/0x7c
>> [<ffffffc0000ef518>] msi_domain_free+0x70/0x88
>> [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
>> [<ffffffc0000ee3ac>] irq_domain_free_irqs+0x108/0x17c
>> [<ffffffc0000efb68>] msi_domain_free_irqs+0x28/0x4c
>> [<ffffffc000369cac>] free_msi_irqs+0xb4/0x1c0
>> [<ffffffc00036adec>] pci_disable_msix+0x3c/0x4c
>> [...]
>> 
>> and I cannot see how this could work on the standard GIC either.
>> 
>> Thomas, Jiang: could you please confirm or infirm my suspicions? My
>> understanding is that irq_domain_free_irqs_top can only be called from
>> the top-level domain.
> Hi Marc,
> 	It indicates that irq_domain_free_irqs_top() is not a good name.
> We have:
> 1) irq_domain_set_hwirq_and_chip() to set irq_chip and chip_data
> 2) irq_domain_set_info() to set irq_chip, chip_data, flow_handler and
>    handler_data;
> 3) irq_domain_reset_irq_data() resets irq_chip and chip_data.
> 4) irq_domain_free_irqs_common() resets irq_chip, chip_data and calls
>    parent domain's domain_ops.free() callback.
> 5) irq_domain_free_irqs_top() resets irq_chip, chip_data, flow handler,
>    handler_data and call parent domain's domain_ops.free() callback.

Yes, and this "call parent domain's free callback" is where the problem
lies. Here, it is called from the innermost domain, with no parent.

> So there two possible improvements here:
> 1) Rename irq_domain_free_irqs_top() with better name, any suggestions?
>    It's named as is because it's always called by the outer-most
>    irqdomains on x86.
> 2) Change irq_domain_free_irqs_common() and irq_domain_free_irqs_top()
>    to call parent domain's domain_ops.free() callback only if parent
>    exists. By this way, they could be used for inner-most irqdomains.
> If OK, I will respin a version 4 patch set based on tip/irq/irqdomain.
> Thoughts?

Checking the parent is probably a safe solution (this is not a hot path
anyway). I don't care much about the name though, and I the only thing I
can think of is irq_domain_free_irqs_reset_flow, which looks so bad it's
not even funny. I'll let the matter rest in your capable hands! ;-)

Thanks,

	M.
Marc Zyngier Nov. 20, 2014, 10:29 a.m. UTC | #6
Hi Joe,

On Thu, Nov 20 2014 at  9:41:51 am GMT, Yingjoe Chen <yingjoe.chen@mediatek.com> wrote:
> Hi Marc,
>
> On Thu, 2014-11-20 at 11:57 +0800, Yingjoe Chen wrote:
>> On Wed, 2014-11-19 at 17:18 +0000, Marc Zyngier wrote:
>> > > +
>> > > +	return 0;
>> > > +}
>> > > +
>> > > +static const struct irq_domain_ops gic_irq_domain_hierarchy_ops = {
>> > > +	.xlate = gic_irq_domain_xlate,
>> > > +	.alloc = gic_irq_domain_alloc,
>> > > +	.free = irq_domain_free_irqs_top,
>> > 
>> > I'm convinced that irq_domain_free_irqs_top is the wrong function to
>> > call here, because you're calling it from the bottom, not the top-level
>> > (it has no parent).
>> 
>> Base on the name, I though this is helper function for top level
>> irq_domain?
>> 
>> > I cannot verify this with your code as I don't a working platform with
>> > GICv2m, but if I enable something similar on GICv3, it dies a very
>> > painful way:
>> > 
>> > Unable to handle kernel NULL pointer dereference at virtual address 00000018
>> > pgd = ffffffc03d059000
>> > [00000018] *pgd=0000000081356003, *pud=0000000081356003,
>> > *pmd=0000000000000000
>> > Internal error: Oops: 96000006 [#1] SMP
>> > Modules linked in:
>> > CPU: 4 PID: 1052 Comm: sh Not tainted 3.18.0-rc4+ #3311
>> > task: ffffffc03e320000 ti: ffffffc001390000 task.ti: ffffffc001390000
>> > PC is at irq_domain_free_irqs_recursive+0x1c/0x80
>> > LR is at irq_domain_free_irqs_common+0x88/0x9c
>> > pc : [<ffffffc0000ed790>] lr : [<ffffffc0000ede20>] pstate: 60000145
>> > [...]
>> > [<ffffffc0000ed790>] irq_domain_free_irqs_recursive+0x1c/0x80
>> > [<ffffffc0000ede1c>] irq_domain_free_irqs_common+0x84/0x9c
>> > [<ffffffc0000ede98>] irq_domain_free_irqs_top+0x64/0x7c <--
>> > gic_domain.free()
>> > [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
>> > [<ffffffc0000ee468>] irq_domain_free_irqs_parent+0x14/0x20
>> > [<ffffffc0003500b8>] its_irq_domain_free+0xc8/0x250
>> > [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
>> > [<ffffffc0000ede1c>] irq_domain_free_irqs_common+0x84/0x9c
>> > [<ffffffc0000ede98>] irq_domain_free_irqs_top+0x64/0x7c
>> > [<ffffffc0000ef518>] msi_domain_free+0x70/0x88
>> > [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
>> > [<ffffffc0000ee3ac>] irq_domain_free_irqs+0x108/0x17c
>> > [<ffffffc0000efb68>] msi_domain_free_irqs+0x28/0x4c
>> > [<ffffffc000369cac>] free_msi_irqs+0xb4/0x1c0
>> > [<ffffffc00036adec>] pci_disable_msix+0x3c/0x4c
>> > [...]
>> > 
>> > and I cannot see how this could work on the standard GIC either.
>> 
>> I'm sorry, I just realize my testcase was too simple, irqs are populated
>> by device tree and never got freed. I'll add that and test it again.
>
> On a second thoughts, unlike the MSI cases, gic_irq_domain_hierarchy_ops
> is only used when we use DT, so we probably will never use the free
> function. Is it OK to remove the free support here?

Well, such thing is coming with GICv2m (SPIs are allocated out of
DT). You can drop it if you want, but I will then have to add it back
(which seems like a waste of time).

I'd prefer if you kept it in with the rest of the conversion.

Thanks,

	M.
Yingjoe Chen Nov. 21, 2014, 3:51 p.m. UTC | #7
Hi,

On Thu, 2014-11-20 at 10:07 +0000, Marc Zyngier wrote:
> On Thu, Nov 20 2014 at  4:26:10 am GMT, Jiang Liu <jiang.liu@linux.intel.com> wrote:
> 
> Hi Jiang,
> 
> > On 2014/11/20 1:18, Marc Zyngier wrote:
> >> Hi Yingjoe,
> >> 
> >> On Wed, Nov 19 2014 at 2:14:08 pm GMT, Yingjoe Chen
> >> <yingjoe.chen@mediatek.com> wrote:
> >>> +
> >>> +static const struct irq_domain_ops gic_irq_domain_hierarchy_ops = {
> >>> +	.xlate = gic_irq_domain_xlate,
> >>> +	.alloc = gic_irq_domain_alloc,
> >>> +	.free = irq_domain_free_irqs_top,
> >> 
> >> I'm convinced that irq_domain_free_irqs_top is the wrong function to
> >> call here, because you're calling it from the bottom, not the top-level
> >> (it has no parent).
> >> 
> >> I cannot verify this with your code as I don't a working platform with
> >> GICv2m, but if I enable something similar on GICv3, it dies a very
> >> painful way:
> >> 
> >> Unable to handle kernel NULL pointer dereference at virtual address 00000018
> >> pgd = ffffffc03d059000
> >> [00000018] *pgd=0000000081356003, *pud=0000000081356003, *pmd=0000000000000000
> >> Internal error: Oops: 96000006 [#1] SMP
> >> Modules linked in:
> >> CPU: 4 PID: 1052 Comm: sh Not tainted 3.18.0-rc4+ #3311
> >> task: ffffffc03e320000 ti: ffffffc001390000 task.ti: ffffffc001390000
> >> PC is at irq_domain_free_irqs_recursive+0x1c/0x80
> >> LR is at irq_domain_free_irqs_common+0x88/0x9c
> >> pc : [<ffffffc0000ed790>] lr : [<ffffffc0000ede20>] pstate: 60000145
> >> [...]
> >> [<ffffffc0000ed790>] irq_domain_free_irqs_recursive+0x1c/0x80
> >> [<ffffffc0000ede1c>] irq_domain_free_irqs_common+0x84/0x9c
> >> [<ffffffc0000ede98>] irq_domain_free_irqs_top+0x64/0x7c  <-- gic_domain.free()
> >> [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
> >> [<ffffffc0000ee468>] irq_domain_free_irqs_parent+0x14/0x20
> >> [<ffffffc0003500b8>] its_irq_domain_free+0xc8/0x250
> >> [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
> >> [<ffffffc0000ede1c>] irq_domain_free_irqs_common+0x84/0x9c
> >> [<ffffffc0000ede98>] irq_domain_free_irqs_top+0x64/0x7c
> >> [<ffffffc0000ef518>] msi_domain_free+0x70/0x88
> >> [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
> >> [<ffffffc0000ee3ac>] irq_domain_free_irqs+0x108/0x17c
> >> [<ffffffc0000efb68>] msi_domain_free_irqs+0x28/0x4c
> >> [<ffffffc000369cac>] free_msi_irqs+0xb4/0x1c0
> >> [<ffffffc00036adec>] pci_disable_msix+0x3c/0x4c
> >> [...]
> >> 
> >> and I cannot see how this could work on the standard GIC either.
> >> 
> >> Thomas, Jiang: could you please confirm or infirm my suspicions? My
> >> understanding is that irq_domain_free_irqs_top can only be called from
> >> the top-level domain.
> > Hi Marc,
> > 	It indicates that irq_domain_free_irqs_top() is not a good name.
> > We have:
> > 1) irq_domain_set_hwirq_and_chip() to set irq_chip and chip_data
> > 2) irq_domain_set_info() to set irq_chip, chip_data, flow_handler and
> >    handler_data;
> > 3) irq_domain_reset_irq_data() resets irq_chip and chip_data.
> > 4) irq_domain_free_irqs_common() resets irq_chip, chip_data and calls
> >    parent domain's domain_ops.free() callback.
> > 5) irq_domain_free_irqs_top() resets irq_chip, chip_data, flow handler,
> >    handler_data and call parent domain's domain_ops.free() callback.
> 
> Yes, and this "call parent domain's free callback" is where the problem
> lies. Here, it is called from the innermost domain, with no parent.
> 
> > So there two possible improvements here:
> > 1) Rename irq_domain_free_irqs_top() with better name, any suggestions?
> >    It's named as is because it's always called by the outer-most
> >    irqdomains on x86.
> > 2) Change irq_domain_free_irqs_common() and irq_domain_free_irqs_top()
> >    to call parent domain's domain_ops.free() callback only if parent
> >    exists. By this way, they could be used for inner-most irqdomains.
> > If OK, I will respin a version 4 patch set based on tip/irq/irqdomain.
> > Thoughts?
> 
> Checking the parent is probably a safe solution (this is not a hot path
> anyway). I don't care much about the name though, and I the only thing I
> can think of is irq_domain_free_irqs_reset_flow, which looks so bad it's
> not even funny. I'll let the matter rest in your capable hands! ;-)

I've applied Jiang's "irqdomain: Enhance irq_domain_free_irqs_common()
to support parentless irqdomain" patch and it did fix the crash.

Thanks Jiang, Marc

Joe.C
Marc Zyngier Nov. 24, 2014, 7:31 p.m. UTC | #8
On 21/11/14 15:51, Yingjoe Chen wrote:
> 
> Hi,
> 
> On Thu, 2014-11-20 at 10:07 +0000, Marc Zyngier wrote:
>> On Thu, Nov 20 2014 at  4:26:10 am GMT, Jiang Liu <jiang.liu@linux.intel.com> wrote:
>>
>> Hi Jiang,
>>
>>> On 2014/11/20 1:18, Marc Zyngier wrote:
>>>> Hi Yingjoe,
>>>>
>>>> On Wed, Nov 19 2014 at 2:14:08 pm GMT, Yingjoe Chen
>>>> <yingjoe.chen@mediatek.com> wrote:
>>>>> +
>>>>> +static const struct irq_domain_ops gic_irq_domain_hierarchy_ops = {
>>>>> +	.xlate = gic_irq_domain_xlate,
>>>>> +	.alloc = gic_irq_domain_alloc,
>>>>> +	.free = irq_domain_free_irqs_top,
>>>>
>>>> I'm convinced that irq_domain_free_irqs_top is the wrong function to
>>>> call here, because you're calling it from the bottom, not the top-level
>>>> (it has no parent).
>>>>
>>>> I cannot verify this with your code as I don't a working platform with
>>>> GICv2m, but if I enable something similar on GICv3, it dies a very
>>>> painful way:
>>>>
>>>> Unable to handle kernel NULL pointer dereference at virtual address 00000018
>>>> pgd = ffffffc03d059000
>>>> [00000018] *pgd=0000000081356003, *pud=0000000081356003, *pmd=0000000000000000
>>>> Internal error: Oops: 96000006 [#1] SMP
>>>> Modules linked in:
>>>> CPU: 4 PID: 1052 Comm: sh Not tainted 3.18.0-rc4+ #3311
>>>> task: ffffffc03e320000 ti: ffffffc001390000 task.ti: ffffffc001390000
>>>> PC is at irq_domain_free_irqs_recursive+0x1c/0x80
>>>> LR is at irq_domain_free_irqs_common+0x88/0x9c
>>>> pc : [<ffffffc0000ed790>] lr : [<ffffffc0000ede20>] pstate: 60000145
>>>> [...]
>>>> [<ffffffc0000ed790>] irq_domain_free_irqs_recursive+0x1c/0x80
>>>> [<ffffffc0000ede1c>] irq_domain_free_irqs_common+0x84/0x9c
>>>> [<ffffffc0000ede98>] irq_domain_free_irqs_top+0x64/0x7c  <-- gic_domain.free()
>>>> [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
>>>> [<ffffffc0000ee468>] irq_domain_free_irqs_parent+0x14/0x20
>>>> [<ffffffc0003500b8>] its_irq_domain_free+0xc8/0x250
>>>> [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
>>>> [<ffffffc0000ede1c>] irq_domain_free_irqs_common+0x84/0x9c
>>>> [<ffffffc0000ede98>] irq_domain_free_irqs_top+0x64/0x7c
>>>> [<ffffffc0000ef518>] msi_domain_free+0x70/0x88
>>>> [<ffffffc0000ed798>] irq_domain_free_irqs_recursive+0x24/0x80
>>>> [<ffffffc0000ee3ac>] irq_domain_free_irqs+0x108/0x17c
>>>> [<ffffffc0000efb68>] msi_domain_free_irqs+0x28/0x4c
>>>> [<ffffffc000369cac>] free_msi_irqs+0xb4/0x1c0
>>>> [<ffffffc00036adec>] pci_disable_msix+0x3c/0x4c
>>>> [...]
>>>>
>>>> and I cannot see how this could work on the standard GIC either.
>>>>
>>>> Thomas, Jiang: could you please confirm or infirm my suspicions? My
>>>> understanding is that irq_domain_free_irqs_top can only be called from
>>>> the top-level domain.
>>> Hi Marc,
>>> 	It indicates that irq_domain_free_irqs_top() is not a good name.
>>> We have:
>>> 1) irq_domain_set_hwirq_and_chip() to set irq_chip and chip_data
>>> 2) irq_domain_set_info() to set irq_chip, chip_data, flow_handler and
>>>    handler_data;
>>> 3) irq_domain_reset_irq_data() resets irq_chip and chip_data.
>>> 4) irq_domain_free_irqs_common() resets irq_chip, chip_data and calls
>>>    parent domain's domain_ops.free() callback.
>>> 5) irq_domain_free_irqs_top() resets irq_chip, chip_data, flow handler,
>>>    handler_data and call parent domain's domain_ops.free() callback.
>>
>> Yes, and this "call parent domain's free callback" is where the problem
>> lies. Here, it is called from the innermost domain, with no parent.
>>
>>> So there two possible improvements here:
>>> 1) Rename irq_domain_free_irqs_top() with better name, any suggestions?
>>>    It's named as is because it's always called by the outer-most
>>>    irqdomains on x86.
>>> 2) Change irq_domain_free_irqs_common() and irq_domain_free_irqs_top()
>>>    to call parent domain's domain_ops.free() callback only if parent
>>>    exists. By this way, they could be used for inner-most irqdomains.
>>> If OK, I will respin a version 4 patch set based on tip/irq/irqdomain.
>>> Thoughts?
>>
>> Checking the parent is probably a safe solution (this is not a hot path
>> anyway). I don't care much about the name though, and I the only thing I
>> can think of is irq_domain_free_irqs_reset_flow, which looks so bad it's
>> not even funny. I'll let the matter rest in your capable hands! ;-)
> 
> I've applied Jiang's "irqdomain: Enhance irq_domain_free_irqs_common()
> to support parentless irqdomain" patch and it did fix the crash.

Excellent.  I think this is pretty much getting there now. Any chance
you could repost this series with the various fixes?

Thanks,

	M.
diff mbox

Patch

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index b21f12f..7f34138 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -5,6 +5,7 @@  config IRQCHIP
 config ARM_GIC
 	bool
 	select IRQ_DOMAIN
+	select IRQ_DOMAIN_HIERARCHY
 	select MULTI_IRQ_HANDLER
 
 config GIC_NON_BANKED
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 38493ff..464dd53 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -788,17 +788,16 @@  static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
 {
 	if (hw < 32) {
 		irq_set_percpu_devid(irq);
-		irq_set_chip_and_handler(irq, &gic_chip,
-					 handle_percpu_devid_irq);
+		irq_domain_set_info(d, irq, hw, &gic_chip, d->host_data,
+				    handle_percpu_devid_irq, NULL, NULL);
 		set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
 	} else {
-		irq_set_chip_and_handler(irq, &gic_chip,
-					 handle_fasteoi_irq);
+		irq_domain_set_info(d, irq, hw, &gic_chip, d->host_data,
+				    handle_fasteoi_irq, NULL, NULL);
 		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 
 		gic_routable_irq_domain_ops->map(d, irq, hw);
 	}
-	irq_set_chip_data(irq, d->host_data);
 	return 0;
 }
 
@@ -858,6 +857,31 @@  static struct notifier_block gic_cpu_notifier = {
 };
 #endif
 
+static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
+				unsigned int nr_irqs, void *arg)
+{
+	int i, ret;
+	irq_hw_number_t hwirq;
+	unsigned int type = IRQ_TYPE_NONE;
+	struct of_phandle_args *irq_data = arg;
+
+	ret = gic_irq_domain_xlate(domain, irq_data->np, irq_data->args,
+				   irq_data->args_count, &hwirq, &type);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < nr_irqs; i++)
+		gic_irq_domain_map(domain, virq+i, hwirq+i);
+
+	return 0;
+}
+
+static const struct irq_domain_ops gic_irq_domain_hierarchy_ops = {
+	.xlate = gic_irq_domain_xlate,
+	.alloc = gic_irq_domain_alloc,
+	.free = irq_domain_free_irqs_top,
+};
+
 static const struct irq_domain_ops gic_irq_domain_ops = {
 	.map = gic_irq_domain_map,
 	.unmap = gic_irq_domain_unmap,
@@ -948,18 +972,6 @@  void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 		gic_cpu_map[i] = 0xff;
 
 	/*
-	 * For primary GICs, skip over SGIs.
-	 * For secondary GICs, skip over PPIs, too.
-	 */
-	if (gic_nr == 0 && (irq_start & 31) > 0) {
-		hwirq_base = 16;
-		if (irq_start != -1)
-			irq_start = (irq_start & ~31) + 16;
-	} else {
-		hwirq_base = 32;
-	}
-
-	/*
 	 * Find out how many interrupts are supported.
 	 * The GIC only supports up to 1020 interrupt sources.
 	 */
@@ -969,10 +981,32 @@  void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 		gic_irqs = 1020;
 	gic->gic_irqs = gic_irqs;
 
-	gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
+	if (node) {		/* DT case */
+		const struct irq_domain_ops *ops =
+					&gic_irq_domain_hierarchy_ops;
+
+		if (!of_property_read_u32(node, "arm,routable-irqs",
+					  &nr_routable_irqs)) {
+			ops = &gic_irq_domain_ops;
+			gic_irqs = nr_routable_irqs;
+		}
+
+		gic->domain = irq_domain_add_linear(node, gic_irqs, ops, gic);
+	} else {		/* Non-DT case */
+		/*
+		 * For primary GICs, skip over SGIs.
+		 * For secondary GICs, skip over PPIs, too.
+		 */
+		if (gic_nr == 0 && (irq_start & 31) > 0) {
+			hwirq_base = 16;
+			if (irq_start != -1)
+				irq_start = (irq_start & ~31) + 16;
+		} else {
+			hwirq_base = 32;
+		}
+
+		gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
 
-	if (of_property_read_u32(node, "arm,routable-irqs",
-				 &nr_routable_irqs)) {
 		irq_base = irq_alloc_descs(irq_start, 16, gic_irqs,
 					   numa_node_id());
 		if (IS_ERR_VALUE(irq_base)) {
@@ -983,10 +1017,6 @@  void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 
 		gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
 					hwirq_base, &gic_irq_domain_ops, gic);
-	} else {
-		gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
-						    &gic_irq_domain_ops,
-						    gic);
 	}
 
 	if (WARN_ON(!gic->domain))