linux-serial.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6] arm pl011 serial: support multi-irq request
@ 2021-08-13  3:31 Bing Fan
  2021-08-13  7:19 ` Greg KH
  2021-08-13 14:37 ` Robin Murphy
  0 siblings, 2 replies; 9+ messages in thread
From: Bing Fan @ 2021-08-13  3:31 UTC (permalink / raw)
  To: gregkh; +Cc: linux-serial, linux-kernel

From: Bing Fan <tombinfan@tencent.com>

In order to make pl011 work better, multiple interrupts are
required, such as TXIM, RXIM, RTIM, error interrupt(FE/PE/BE/OE);
at the same time, pl011 to GIC does not merge the interrupt
lines(each serial-interrupt corresponding to different GIC hardware
interrupt), so need to enable and request multiple gic interrupt
numbers in the driver.

Signed-off-by: Bing Fan <tombinfan@tencent.com>
---
 drivers/tty/serial/amba-pl011.c | 39 +++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index e14f3378b8a0..eaac3431459c 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1701,6 +1701,41 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
 	}
 }
 
+static void pl011_release_multi_irqs(struct uart_amba_port *uap, unsigned int max_cnt)
+{
+	struct amba_device *amba_dev = container_of(uap->port.dev, struct amba_device, dev);
+	int i;
+
+	for (i = 0; i < max_cnt; i++)
+		if (amba_dev->irq[i])
+			free_irq(amba_dev->irq[i], uap);
+}
+
+static int pl011_allocate_multi_irqs(struct uart_amba_port *uap)
+{
+	int ret = 0;
+	int i;
+	unsigned int virq;
+	struct amba_device *amba_dev = container_of(uap->port.dev, struct amba_device, dev);
+
+	pl011_write(uap->im, uap, REG_IMSC);
+
+	for (i = 0; i < AMBA_NR_IRQS; i++) {
+		virq = amba_dev->irq[i];
+		if (virq == 0)
+			break;
+
+		ret = request_irq(virq, pl011_int, IRQF_SHARED, dev_name(&amba_dev->dev), uap);
+		if (ret) {
+			dev_err(uap->port.dev, "request %u interrupt failed\n", virq);
+			pl011_release_multi_irqs(uap, i - 1);
+			break;
+		}
+	}
+
+	return ret;
+}
+
 static int pl011_allocate_irq(struct uart_amba_port *uap)
 {
 	pl011_write(uap->im, uap, REG_IMSC);
@@ -1753,7 +1788,7 @@ static int pl011_startup(struct uart_port *port)
 	if (retval)
 		goto clk_dis;
 
-	retval = pl011_allocate_irq(uap);
+	retval = pl011_allocate_multi_irqs(uap);
 	if (retval)
 		goto clk_dis;
 
@@ -1864,7 +1899,7 @@ static void pl011_shutdown(struct uart_port *port)
 
 	pl011_dma_shutdown(uap);
 
-	free_irq(uap->port.irq, uap);
+	pl011_release_multi_irqs(uap, AMBA_NR_IRQS);
 
 	pl011_disable_uart(uap);
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v6] arm pl011 serial: support multi-irq request
  2021-08-13  3:31 [PATCH v6] arm pl011 serial: support multi-irq request Bing Fan
@ 2021-08-13  7:19 ` Greg KH
       [not found]   ` <9c3a4336-b6c4-d96e-9a9d-8001dddcee20@gmail.com>
  2021-08-13 14:37 ` Robin Murphy
  1 sibling, 1 reply; 9+ messages in thread
From: Greg KH @ 2021-08-13  7:19 UTC (permalink / raw)
  To: Bing Fan; +Cc: linux-serial, linux-kernel

On Fri, Aug 13, 2021 at 11:31:30AM +0800, Bing Fan wrote:
> From: Bing Fan <tombinfan@tencent.com>
> 
> In order to make pl011 work better, multiple interrupts are
> required, such as TXIM, RXIM, RTIM, error interrupt(FE/PE/BE/OE);
> at the same time, pl011 to GIC does not merge the interrupt
> lines(each serial-interrupt corresponding to different GIC hardware
> interrupt), so need to enable and request multiple gic interrupt
> numbers in the driver.
> 
> Signed-off-by: Bing Fan <tombinfan@tencent.com>
> ---
>  drivers/tty/serial/amba-pl011.c | 39 +++++++++++++++++++++++++++++++--
>  1 file changed, 37 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
> index e14f3378b8a0..eaac3431459c 100644
> --- a/drivers/tty/serial/amba-pl011.c
> +++ b/drivers/tty/serial/amba-pl011.c
> @@ -1701,6 +1701,41 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
>  	}
>  }
>  
> +static void pl011_release_multi_irqs(struct uart_amba_port *uap, unsigned int max_cnt)
> +{
> +	struct amba_device *amba_dev = container_of(uap->port.dev, struct amba_device, dev);
> +	int i;
> +
> +	for (i = 0; i < max_cnt; i++)
> +		if (amba_dev->irq[i])
> +			free_irq(amba_dev->irq[i], uap);
> +}
> +
> +static int pl011_allocate_multi_irqs(struct uart_amba_port *uap)
> +{
> +	int ret = 0;
> +	int i;
> +	unsigned int virq;
> +	struct amba_device *amba_dev = container_of(uap->port.dev, struct amba_device, dev);
> +
> +	pl011_write(uap->im, uap, REG_IMSC);
> +
> +	for (i = 0; i < AMBA_NR_IRQS; i++) {
> +		virq = amba_dev->irq[i];
> +		if (virq == 0)
> +			break;
> +
> +		ret = request_irq(virq, pl011_int, IRQF_SHARED, dev_name(&amba_dev->dev), uap);
> +		if (ret) {
> +			dev_err(uap->port.dev, "request %u interrupt failed\n", virq);
> +			pl011_release_multi_irqs(uap, i - 1);
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}

This function looks identical to pl011_allocate_irq(), so what is the
difference here?  Why is this still needed at all?  What does it do that
is different from pl011_allocate_irq()?

confused,

greg k-h

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v6] arm pl011 serial: support multi-irq request
       [not found]   ` <9c3a4336-b6c4-d96e-9a9d-8001dddcee20@gmail.com>
@ 2021-08-13  8:17     ` Greg KH
  2021-08-13 14:08       ` Robin Murphy
  0 siblings, 1 reply; 9+ messages in thread
From: Greg KH @ 2021-08-13  8:17 UTC (permalink / raw)
  To: Bing Fan; +Cc: linux-serial, linux-kernel

On Fri, Aug 13, 2021 at 03:56:01PM +0800, Bing Fan wrote:
> 
> 在 8/13/2021 15:19, Greg KH 写道:
> > On Fri, Aug 13, 2021 at 11:31:30AM +0800, Bing Fan wrote:
> > > From: Bing Fan <tombinfan@tencent.com>
> > > 
> > > In order to make pl011 work better, multiple interrupts are
> > > required, such as TXIM, RXIM, RTIM, error interrupt(FE/PE/BE/OE);
> > > at the same time, pl011 to GIC does not merge the interrupt
> > > lines(each serial-interrupt corresponding to different GIC hardware
> > > interrupt), so need to enable and request multiple gic interrupt
> > > numbers in the driver.
> > > 
> > > Signed-off-by: Bing Fan <tombinfan@tencent.com>
> > > ---
> > >   drivers/tty/serial/amba-pl011.c | 39 +++++++++++++++++++++++++++++++--
> > >   1 file changed, 37 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
> > > index e14f3378b8a0..eaac3431459c 100644
> > > --- a/drivers/tty/serial/amba-pl011.c
> > > +++ b/drivers/tty/serial/amba-pl011.c
> > > @@ -1701,6 +1701,41 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
> > >   	}
> > >   }
> > > +static void pl011_release_multi_irqs(struct uart_amba_port *uap, unsigned int max_cnt)
> > > +{
> > > +	struct amba_device *amba_dev = container_of(uap->port.dev, struct amba_device, dev);
> > > +	int i;
> > > +
> > > +	for (i = 0; i < max_cnt; i++)
> > > +		if (amba_dev->irq[i])
> > > +			free_irq(amba_dev->irq[i], uap);
> > > +}
> > > +
> > > +static int pl011_allocate_multi_irqs(struct uart_amba_port *uap)
> > > +{
> > > +	int ret = 0;
> > > +	int i;
> > > +	unsigned int virq;
> > > +	struct amba_device *amba_dev = container_of(uap->port.dev, struct amba_device, dev);
> > > +
> > > +	pl011_write(uap->im, uap, REG_IMSC);
> > > +
> > > +	for (i = 0; i < AMBA_NR_IRQS; i++) {
> > > +		virq = amba_dev->irq[i];
> > > +		if (virq == 0)
> > > +			break;
> > > +
> > > +		ret = request_irq(virq, pl011_int, IRQF_SHARED, dev_name(&amba_dev->dev), uap);
> > > +		if (ret) {
> > > +			dev_err(uap->port.dev, "request %u interrupt failed\n", virq);
> > > +			pl011_release_multi_irqs(uap, i - 1);
> > > +			break;
> > > +		}
> > > +	}
> > > +
> > > +	return ret;
> > > +}
> > This function looks identical to pl011_allocate_irq(), so what is the
> > difference here?  Why is this still needed at all?  What does it do that
> > is different from pl011_allocate_irq()?
> 
> The v6-patch is based on master of
> git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git, not tty-next.

Always submit patches based on tty-next if you want them accepted into
that tree.

> As below, the pl011_allocate_irq function supports single irq request only,
> which different from pl011_allocate_multi_irqs.
> 
> static int pl011_allocate_irq(struct uart_amba_port *uap)
> {
>     pl011_write(uap->im, uap, REG_IMSC);
> 
>     return request_irq(uap->port.irq, pl011_int, IRQF_SHARED, "uart-pl011",
> uap);
> }

Ok, but that does not reflect what is in my tree to be merged for
5.15-rc1.  What is wrong with the code in there that is incorrect and
needs to be changed?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v6] arm pl011 serial: support multi-irq request
  2021-08-13  8:17     ` Greg KH
@ 2021-08-13 14:08       ` Robin Murphy
  2021-08-13 15:04         ` Greg KH
  0 siblings, 1 reply; 9+ messages in thread
From: Robin Murphy @ 2021-08-13 14:08 UTC (permalink / raw)
  To: Greg KH, Bing Fan; +Cc: linux-serial, linux-kernel, Qian Cai

Hi Greg,

On 2021-08-13 09:17, Greg KH wrote:
> On Fri, Aug 13, 2021 at 03:56:01PM +0800, Bing Fan wrote:
>>
>> 在 8/13/2021 15:19, Greg KH 写道:
>>> On Fri, Aug 13, 2021 at 11:31:30AM +0800, Bing Fan wrote:
>>>> From: Bing Fan <tombinfan@tencent.com>
>>>>
>>>> In order to make pl011 work better, multiple interrupts are
>>>> required, such as TXIM, RXIM, RTIM, error interrupt(FE/PE/BE/OE);
>>>> at the same time, pl011 to GIC does not merge the interrupt
>>>> lines(each serial-interrupt corresponding to different GIC hardware
>>>> interrupt), so need to enable and request multiple gic interrupt
>>>> numbers in the driver.
>>>>
>>>> Signed-off-by: Bing Fan <tombinfan@tencent.com>
>>>> ---
>>>>    drivers/tty/serial/amba-pl011.c | 39 +++++++++++++++++++++++++++++++--
>>>>    1 file changed, 37 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
>>>> index e14f3378b8a0..eaac3431459c 100644
>>>> --- a/drivers/tty/serial/amba-pl011.c
>>>> +++ b/drivers/tty/serial/amba-pl011.c
>>>> @@ -1701,6 +1701,41 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
>>>>    	}
>>>>    }
>>>> +static void pl011_release_multi_irqs(struct uart_amba_port *uap, unsigned int max_cnt)
>>>> +{
>>>> +	struct amba_device *amba_dev = container_of(uap->port.dev, struct amba_device, dev);
>>>> +	int i;
>>>> +
>>>> +	for (i = 0; i < max_cnt; i++)
>>>> +		if (amba_dev->irq[i])
>>>> +			free_irq(amba_dev->irq[i], uap);
>>>> +}
>>>> +
>>>> +static int pl011_allocate_multi_irqs(struct uart_amba_port *uap)
>>>> +{
>>>> +	int ret = 0;
>>>> +	int i;
>>>> +	unsigned int virq;
>>>> +	struct amba_device *amba_dev = container_of(uap->port.dev, struct amba_device, dev);
>>>> +
>>>> +	pl011_write(uap->im, uap, REG_IMSC);
>>>> +
>>>> +	for (i = 0; i < AMBA_NR_IRQS; i++) {
>>>> +		virq = amba_dev->irq[i];
>>>> +		if (virq == 0)
>>>> +			break;
>>>> +
>>>> +		ret = request_irq(virq, pl011_int, IRQF_SHARED, dev_name(&amba_dev->dev), uap);
>>>> +		if (ret) {
>>>> +			dev_err(uap->port.dev, "request %u interrupt failed\n", virq);
>>>> +			pl011_release_multi_irqs(uap, i - 1);
>>>> +			break;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	return ret;
>>>> +}
>>> This function looks identical to pl011_allocate_irq(), so what is the
>>> difference here?  Why is this still needed at all?  What does it do that
>>> is different from pl011_allocate_irq()?
>>
>> The v6-patch is based on master of
>> git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git, not tty-next.
> 
> Always submit patches based on tty-next if you want them accepted into
> that tree.
> 
>> As below, the pl011_allocate_irq function supports single irq request only,
>> which different from pl011_allocate_multi_irqs.
>>
>> static int pl011_allocate_irq(struct uart_amba_port *uap)
>> {
>>      pl011_write(uap->im, uap, REG_IMSC);
>>
>>      return request_irq(uap->port.irq, pl011_int, IRQF_SHARED, "uart-pl011",
>> uap);
>> }
> 
> Ok, but that does not reflect what is in my tree to be merged for
> 5.15-rc1.  What is wrong with the code in there that is incorrect and
> needs to be changed?

As reported by Qian Cai, it blows up on ACPI-based systems by assuming 
port.dev is an amba_device when in fact in that situation it's a 
platform_device. If you're able to drop the current patch from your tree 
that would probably be the best thing to do for the moment.

Cheers,
Robin.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v6] arm pl011 serial: support multi-irq request
  2021-08-13  3:31 [PATCH v6] arm pl011 serial: support multi-irq request Bing Fan
  2021-08-13  7:19 ` Greg KH
@ 2021-08-13 14:37 ` Robin Murphy
       [not found]   ` <5b68f69c-f9cd-b0a4-45dd-d6db6d09fd65@gmail.com>
  2021-08-16 10:34   ` Russell King (Oracle)
  1 sibling, 2 replies; 9+ messages in thread
From: Robin Murphy @ 2021-08-13 14:37 UTC (permalink / raw)
  To: Bing Fan, gregkh, Russell King; +Cc: linux-serial, linux-kernel

[ +Russell as the listed PL011 maintainer ]

On 2021-08-13 04:31, Bing Fan wrote:
> From: Bing Fan <tombinfan@tencent.com>
> 
> In order to make pl011 work better, multiple interrupts are
> required, such as TXIM, RXIM, RTIM, error interrupt(FE/PE/BE/OE);
> at the same time, pl011 to GIC does not merge the interrupt
> lines(each serial-interrupt corresponding to different GIC hardware
> interrupt), so need to enable and request multiple gic interrupt
> numbers in the driver.
> 
> Signed-off-by: Bing Fan <tombinfan@tencent.com>
> ---
>   drivers/tty/serial/amba-pl011.c | 39 +++++++++++++++++++++++++++++++--
>   1 file changed, 37 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
> index e14f3378b8a0..eaac3431459c 100644
> --- a/drivers/tty/serial/amba-pl011.c
> +++ b/drivers/tty/serial/amba-pl011.c
> @@ -1701,6 +1701,41 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
>   	}
>   }
>   
> +static void pl011_release_multi_irqs(struct uart_amba_port *uap, unsigned int max_cnt)
> +{
> +	struct amba_device *amba_dev = container_of(uap->port.dev, struct amba_device, dev);
> +	int i;
> +
> +	for (i = 0; i < max_cnt; i++)
> +		if (amba_dev->irq[i])
> +			free_irq(amba_dev->irq[i], uap);

When you request the IRQs you break at the first zero, so this could 
potentially try to free IRQs that you haven't requested, if there happen 
to be any nonzero values beyond that. Maybe that can never happen, but 
there seems little need for deliberate inconsistency here.

> +}
> +
> +static int pl011_allocate_multi_irqs(struct uart_amba_port *uap)
> +{
> +	int ret = 0;
> +	int i;
> +	unsigned int virq;
> +	struct amba_device *amba_dev = container_of(uap->port.dev, struct amba_device, dev);
> +
> +	pl011_write(uap->im, uap, REG_IMSC);
> +
> +	for (i = 0; i < AMBA_NR_IRQS; i++) {

It's not clear where these extra IRQs are expected to come from given 
that the DT binding explicitly defines only one :/

> +		virq = amba_dev->irq[i];
> +		if (virq == 0)
> +			break;
> +
> +		ret = request_irq(virq, pl011_int, IRQF_SHARED, dev_name(&amba_dev->dev), uap);

Note that using dev_name() here technically breaks user ABI - scripts 
looking in /proc for an irq named "uart-pl011" will no longer find it.

Furthermore, the "dev" cookie passed to request_irq is supposed to be 
globally unique, which "uap" isn't once you start registering it 
multiple times. If firmware did describe all the individual PL011 IRQ 
outputs on a system where they are muxed to the same physical IRQ 
anyway, you'd end up registering ambiguous IRQ actions here. Of course 
in practice you might still get away with that, but it is technically wrong.

Robin.

> +		if (ret) {
> +			dev_err(uap->port.dev, "request %u interrupt failed\n", virq);
> +			pl011_release_multi_irqs(uap, i - 1);
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
>   static int pl011_allocate_irq(struct uart_amba_port *uap)
>   {
>   	pl011_write(uap->im, uap, REG_IMSC);
> @@ -1753,7 +1788,7 @@ static int pl011_startup(struct uart_port *port)
>   	if (retval)
>   		goto clk_dis;
>   
> -	retval = pl011_allocate_irq(uap);
> +	retval = pl011_allocate_multi_irqs(uap);
>   	if (retval)
>   		goto clk_dis;
>   
> @@ -1864,7 +1899,7 @@ static void pl011_shutdown(struct uart_port *port)
>   
>   	pl011_dma_shutdown(uap);
>   
> -	free_irq(uap->port.irq, uap);
> +	pl011_release_multi_irqs(uap, AMBA_NR_IRQS);
>   
>   	pl011_disable_uart(uap);
>   
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v6] arm pl011 serial: support multi-irq request
  2021-08-13 14:08       ` Robin Murphy
@ 2021-08-13 15:04         ` Greg KH
  2021-08-13 15:17           ` Robin Murphy
  0 siblings, 1 reply; 9+ messages in thread
From: Greg KH @ 2021-08-13 15:04 UTC (permalink / raw)
  To: Robin Murphy; +Cc: Bing Fan, linux-serial, linux-kernel, Qian Cai

On Fri, Aug 13, 2021 at 03:08:48PM +0100, Robin Murphy wrote:
> Hi Greg,
> 
> On 2021-08-13 09:17, Greg KH wrote:
> > On Fri, Aug 13, 2021 at 03:56:01PM +0800, Bing Fan wrote:
> > > 
> > > 在 8/13/2021 15:19, Greg KH 写道:
> > > > On Fri, Aug 13, 2021 at 11:31:30AM +0800, Bing Fan wrote:
> > > > > From: Bing Fan <tombinfan@tencent.com>
> > > > > 
> > > > > In order to make pl011 work better, multiple interrupts are
> > > > > required, such as TXIM, RXIM, RTIM, error interrupt(FE/PE/BE/OE);
> > > > > at the same time, pl011 to GIC does not merge the interrupt
> > > > > lines(each serial-interrupt corresponding to different GIC hardware
> > > > > interrupt), so need to enable and request multiple gic interrupt
> > > > > numbers in the driver.
> > > > > 
> > > > > Signed-off-by: Bing Fan <tombinfan@tencent.com>
> > > > > ---
> > > > >    drivers/tty/serial/amba-pl011.c | 39 +++++++++++++++++++++++++++++++--
> > > > >    1 file changed, 37 insertions(+), 2 deletions(-)
> > > > > 
> > > > > diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
> > > > > index e14f3378b8a0..eaac3431459c 100644
> > > > > --- a/drivers/tty/serial/amba-pl011.c
> > > > > +++ b/drivers/tty/serial/amba-pl011.c
> > > > > @@ -1701,6 +1701,41 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
> > > > >    	}
> > > > >    }
> > > > > +static void pl011_release_multi_irqs(struct uart_amba_port *uap, unsigned int max_cnt)
> > > > > +{
> > > > > +	struct amba_device *amba_dev = container_of(uap->port.dev, struct amba_device, dev);
> > > > > +	int i;
> > > > > +
> > > > > +	for (i = 0; i < max_cnt; i++)
> > > > > +		if (amba_dev->irq[i])
> > > > > +			free_irq(amba_dev->irq[i], uap);
> > > > > +}
> > > > > +
> > > > > +static int pl011_allocate_multi_irqs(struct uart_amba_port *uap)
> > > > > +{
> > > > > +	int ret = 0;
> > > > > +	int i;
> > > > > +	unsigned int virq;
> > > > > +	struct amba_device *amba_dev = container_of(uap->port.dev, struct amba_device, dev);
> > > > > +
> > > > > +	pl011_write(uap->im, uap, REG_IMSC);
> > > > > +
> > > > > +	for (i = 0; i < AMBA_NR_IRQS; i++) {
> > > > > +		virq = amba_dev->irq[i];
> > > > > +		if (virq == 0)
> > > > > +			break;
> > > > > +
> > > > > +		ret = request_irq(virq, pl011_int, IRQF_SHARED, dev_name(&amba_dev->dev), uap);
> > > > > +		if (ret) {
> > > > > +			dev_err(uap->port.dev, "request %u interrupt failed\n", virq);
> > > > > +			pl011_release_multi_irqs(uap, i - 1);
> > > > > +			break;
> > > > > +		}
> > > > > +	}
> > > > > +
> > > > > +	return ret;
> > > > > +}
> > > > This function looks identical to pl011_allocate_irq(), so what is the
> > > > difference here?  Why is this still needed at all?  What does it do that
> > > > is different from pl011_allocate_irq()?
> > > 
> > > The v6-patch is based on master of
> > > git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git, not tty-next.
> > 
> > Always submit patches based on tty-next if you want them accepted into
> > that tree.
> > 
> > > As below, the pl011_allocate_irq function supports single irq request only,
> > > which different from pl011_allocate_multi_irqs.
> > > 
> > > static int pl011_allocate_irq(struct uart_amba_port *uap)
> > > {
> > >      pl011_write(uap->im, uap, REG_IMSC);
> > > 
> > >      return request_irq(uap->port.irq, pl011_int, IRQF_SHARED, "uart-pl011",
> > > uap);
> > > }
> > 
> > Ok, but that does not reflect what is in my tree to be merged for
> > 5.15-rc1.  What is wrong with the code in there that is incorrect and
> > needs to be changed?
> 
> As reported by Qian Cai, it blows up on ACPI-based systems by assuming
> port.dev is an amba_device when in fact in that situation it's a
> platform_device. If you're able to drop the current patch from your tree
> that would probably be the best thing to do for the moment.

I have not seen any such bug report.

If something needs to be reverted in linux-next, (i.e. in my tty-next
branch), please let me know.  Ideally by sending a pathc to do so...

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v6] arm pl011 serial: support multi-irq request
  2021-08-13 15:04         ` Greg KH
@ 2021-08-13 15:17           ` Robin Murphy
  0 siblings, 0 replies; 9+ messages in thread
From: Robin Murphy @ 2021-08-13 15:17 UTC (permalink / raw)
  To: Greg KH, Qian Cai; +Cc: Bing Fan, linux-serial, linux-kernel

On 2021-08-13 16:04, Greg KH wrote:
> On Fri, Aug 13, 2021 at 03:08:48PM +0100, Robin Murphy wrote:
>> Hi Greg,
>>
>> On 2021-08-13 09:17, Greg KH wrote:
>>> On Fri, Aug 13, 2021 at 03:56:01PM +0800, Bing Fan wrote:
>>>>
>>>> 在 8/13/2021 15:19, Greg KH 写道:
>>>>> On Fri, Aug 13, 2021 at 11:31:30AM +0800, Bing Fan wrote:
>>>>>> From: Bing Fan <tombinfan@tencent.com>
>>>>>>
>>>>>> In order to make pl011 work better, multiple interrupts are
>>>>>> required, such as TXIM, RXIM, RTIM, error interrupt(FE/PE/BE/OE);
>>>>>> at the same time, pl011 to GIC does not merge the interrupt
>>>>>> lines(each serial-interrupt corresponding to different GIC hardware
>>>>>> interrupt), so need to enable and request multiple gic interrupt
>>>>>> numbers in the driver.
>>>>>>
>>>>>> Signed-off-by: Bing Fan <tombinfan@tencent.com>
>>>>>> ---
>>>>>>     drivers/tty/serial/amba-pl011.c | 39 +++++++++++++++++++++++++++++++--
>>>>>>     1 file changed, 37 insertions(+), 2 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
>>>>>> index e14f3378b8a0..eaac3431459c 100644
>>>>>> --- a/drivers/tty/serial/amba-pl011.c
>>>>>> +++ b/drivers/tty/serial/amba-pl011.c
>>>>>> @@ -1701,6 +1701,41 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
>>>>>>     	}
>>>>>>     }
>>>>>> +static void pl011_release_multi_irqs(struct uart_amba_port *uap, unsigned int max_cnt)
>>>>>> +{
>>>>>> +	struct amba_device *amba_dev = container_of(uap->port.dev, struct amba_device, dev);
>>>>>> +	int i;
>>>>>> +
>>>>>> +	for (i = 0; i < max_cnt; i++)
>>>>>> +		if (amba_dev->irq[i])
>>>>>> +			free_irq(amba_dev->irq[i], uap);
>>>>>> +}
>>>>>> +
>>>>>> +static int pl011_allocate_multi_irqs(struct uart_amba_port *uap)
>>>>>> +{
>>>>>> +	int ret = 0;
>>>>>> +	int i;
>>>>>> +	unsigned int virq;
>>>>>> +	struct amba_device *amba_dev = container_of(uap->port.dev, struct amba_device, dev);
>>>>>> +
>>>>>> +	pl011_write(uap->im, uap, REG_IMSC);
>>>>>> +
>>>>>> +	for (i = 0; i < AMBA_NR_IRQS; i++) {
>>>>>> +		virq = amba_dev->irq[i];
>>>>>> +		if (virq == 0)
>>>>>> +			break;
>>>>>> +
>>>>>> +		ret = request_irq(virq, pl011_int, IRQF_SHARED, dev_name(&amba_dev->dev), uap);
>>>>>> +		if (ret) {
>>>>>> +			dev_err(uap->port.dev, "request %u interrupt failed\n", virq);
>>>>>> +			pl011_release_multi_irqs(uap, i - 1);
>>>>>> +			break;
>>>>>> +		}
>>>>>> +	}
>>>>>> +
>>>>>> +	return ret;
>>>>>> +}
>>>>> This function looks identical to pl011_allocate_irq(), so what is the
>>>>> difference here?  Why is this still needed at all?  What does it do that
>>>>> is different from pl011_allocate_irq()?
>>>>
>>>> The v6-patch is based on master of
>>>> git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git, not tty-next.
>>>
>>> Always submit patches based on tty-next if you want them accepted into
>>> that tree.
>>>
>>>> As below, the pl011_allocate_irq function supports single irq request only,
>>>> which different from pl011_allocate_multi_irqs.
>>>>
>>>> static int pl011_allocate_irq(struct uart_amba_port *uap)
>>>> {
>>>>       pl011_write(uap->im, uap, REG_IMSC);
>>>>
>>>>       return request_irq(uap->port.irq, pl011_int, IRQF_SHARED, "uart-pl011",
>>>> uap);
>>>> }
>>>
>>> Ok, but that does not reflect what is in my tree to be merged for
>>> 5.15-rc1.  What is wrong with the code in there that is incorrect and
>>> needs to be changed?
>>
>> As reported by Qian Cai, it blows up on ACPI-based systems by assuming
>> port.dev is an amba_device when in fact in that situation it's a
>> platform_device. If you're able to drop the current patch from your tree
>> that would probably be the best thing to do for the moment.
> 
> I have not seen any such bug report.

It's the thread on the v5 patch that you've just replied to ;)

> If something needs to be reverted in linux-next, (i.e. in my tty-next
> branch), please let me know.  Ideally by sending a pathc to do so...

Since I'm only really involved here off the back of a drive-by review 
comment, I'll leave that up to Qian.

Cheers,
Robin.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v6] arm pl011 serial: support multi-irq request
       [not found]   ` <5b68f69c-f9cd-b0a4-45dd-d6db6d09fd65@gmail.com>
@ 2021-08-16 10:19     ` Robin Murphy
  0 siblings, 0 replies; 9+ messages in thread
From: Robin Murphy @ 2021-08-16 10:19 UTC (permalink / raw)
  To: Bing Fan, gregkh, Russell King; +Cc: linux-serial, linux-kernel

On 2021-08-16 08:42, Bing Fan wrote:
> 
> At present, i think a focus of our discussion is whether this patch is 
> necessary.
> 
> As for the other points you mentioned, I think they can be used as code 
> review comments.
> 
> 
> Yes, as you described below, most dts files have only one interrupt, but 
> not all platforms are like this.
> 
> The scene I'm encountering now is the latter: the interrupt lines of the 
> uart is connected to the gic separately
> 
> so the dts should be define like this:
> 
>                 duart1: serial@5E139000 {
>                          compatible = "arm,pl011", "arm,primecell";
>                          reg = <0x00 0x5E139000 0x0 0x1000>;
>                          interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>,
>                                  <GIC_SPI 179 IRQ_TYPE_LEVEL_HIGH>,
>                                  <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>,
>                                  <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH>;
>                          clocks = <&sysclk>;
>                          clock-names = "apb_pclk";
>                  };

Apologies for being unclear - the point I was implying is that of course 
you can do that in practice, but if you run that DTS through `make 
dtbs_check` it will fail. The binding needs extending to make it valid 
to specify more than one interrupt, and that's a separate patch and 
discussion in itself (simply increasing "maxitems" for the "interrupts" 
property is not enough to be robust).

Robin.

> The current tty-master code cannot meet this scenario, so I submitted 
> this patch.
> 
> 
> 
> 
> 
> 在 2021/8/13 下午10:37, Robin Murphy 写道:
>> [ +Russell as the listed PL011 maintainer ]
>>
>> On 2021-08-13 04:31, Bing Fan wrote:
>>> From: Bing Fan <tombinfan@tencent.com>
>>>
>>> In order to make pl011 work better, multiple interrupts are
>>> required, such as TXIM, RXIM, RTIM, error interrupt(FE/PE/BE/OE);
>>> at the same time, pl011 to GIC does not merge the interrupt
>>> lines(each serial-interrupt corresponding to different GIC hardware
>>> interrupt), so need to enable and request multiple gic interrupt
>>> numbers in the driver.
>>>
>>> Signed-off-by: Bing Fan <tombinfan@tencent.com>
>>> ---
>>>   drivers/tty/serial/amba-pl011.c | 39 +++++++++++++++++++++++++++++++--
>>>   1 file changed, 37 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/tty/serial/amba-pl011.c 
>>> b/drivers/tty/serial/amba-pl011.c
>>> index e14f3378b8a0..eaac3431459c 100644
>>> --- a/drivers/tty/serial/amba-pl011.c
>>> +++ b/drivers/tty/serial/amba-pl011.c
>>> @@ -1701,6 +1701,41 @@ static void pl011_write_lcr_h(struct 
>>> uart_amba_port *uap, unsigned int lcr_h)
>>>       }
>>>   }
>>>   +static void pl011_release_multi_irqs(struct uart_amba_port *uap, 
>>> unsigned int max_cnt)
>>> +{
>>> +    struct amba_device *amba_dev = container_of(uap->port.dev, 
>>> struct amba_device, dev);
>>> +    int i;
>>> +
>>> +    for (i = 0; i < max_cnt; i++)
>>> +        if (amba_dev->irq[i])
>>> +            free_irq(amba_dev->irq[i], uap);
>>
>> When you request the IRQs you break at the first zero, so this could 
>> potentially try to free IRQs that you haven't requested, if there 
>> happen to be any nonzero values beyond that. Maybe that can never 
>> happen, but there seems little need for deliberate inconsistency here.
>>
>>> +}
>>> +
>>> +static int pl011_allocate_multi_irqs(struct uart_amba_port *uap)
>>> +{
>>> +    int ret = 0;
>>> +    int i;
>>> +    unsigned int virq;
>>> +    struct amba_device *amba_dev = container_of(uap->port.dev, 
>>> struct amba_device, dev);
>>> +
>>> +    pl011_write(uap->im, uap, REG_IMSC);
>>> +
>>> +    for (i = 0; i < AMBA_NR_IRQS; i++) {
>>
>> It's not clear where these extra IRQs are expected to come from given 
>> that the DT binding explicitly defines only one :/
>>
>>> +        virq = amba_dev->irq[i];
>>> +        if (virq == 0)
>>> +            break;
>>> +
>>> +        ret = request_irq(virq, pl011_int, IRQF_SHARED, 
>>> dev_name(&amba_dev->dev), uap);
>>
>> Note that using dev_name() here technically breaks user ABI - scripts 
>> looking in /proc for an irq named "uart-pl011" will no longer find it.
>>
>> Furthermore, the "dev" cookie passed to request_irq is supposed to be 
>> globally unique, which "uap" isn't once you start registering it 
>> multiple times. If firmware did describe all the individual PL011 IRQ 
>> outputs on a system where they are muxed to the same physical IRQ 
>> anyway, you'd end up registering ambiguous IRQ actions here. Of course 
>> in practice you might still get away with that, but it is technically 
>> wrong.
>>
>> Robin.
>>
>>> +        if (ret) {
>>> +            dev_err(uap->port.dev, "request %u interrupt failed\n", 
>>> virq);
>>> +            pl011_release_multi_irqs(uap, i - 1);
>>> +            break;
>>> +        }
>>> +    }
>>> +
>>> +    return ret;
>>> +}
>>> +
>>>   static int pl011_allocate_irq(struct uart_amba_port *uap)
>>>   {
>>>       pl011_write(uap->im, uap, REG_IMSC);
>>> @@ -1753,7 +1788,7 @@ static int pl011_startup(struct uart_port *port)
>>>       if (retval)
>>>           goto clk_dis;
>>>   -    retval = pl011_allocate_irq(uap);
>>> +    retval = pl011_allocate_multi_irqs(uap);
>>>       if (retval)
>>>           goto clk_dis;
>>>   @@ -1864,7 +1899,7 @@ static void pl011_shutdown(struct uart_port 
>>> *port)
>>>         pl011_dma_shutdown(uap);
>>>   -    free_irq(uap->port.irq, uap);
>>> +    pl011_release_multi_irqs(uap, AMBA_NR_IRQS);
>>>         pl011_disable_uart(uap);
>>>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v6] arm pl011 serial: support multi-irq request
  2021-08-13 14:37 ` Robin Murphy
       [not found]   ` <5b68f69c-f9cd-b0a4-45dd-d6db6d09fd65@gmail.com>
@ 2021-08-16 10:34   ` Russell King (Oracle)
  1 sibling, 0 replies; 9+ messages in thread
From: Russell King (Oracle) @ 2021-08-16 10:34 UTC (permalink / raw)
  To: Robin Murphy; +Cc: Bing Fan, gregkh, linux-serial, linux-kernel

On Fri, Aug 13, 2021 at 03:37:16PM +0100, Robin Murphy wrote:
> > +static int pl011_allocate_multi_irqs(struct uart_amba_port *uap)
> > +{
> > +	int ret = 0;
> > +	int i;
> > +	unsigned int virq;
> > +	struct amba_device *amba_dev = container_of(uap->port.dev, struct amba_device, dev);
> > +
> > +	pl011_write(uap->im, uap, REG_IMSC);
> > +
> > +	for (i = 0; i < AMBA_NR_IRQS; i++) {
> 
> It's not clear where these extra IRQs are expected to come from given that
> the DT binding explicitly defines only one :/

The DT binding (and driver) was written assuming that people wouldn't
use the individual interrupts - but I guess someone decided it was a
good idea to have a bazillion interrupt signals going to your interrupt
controller from something as simple as a UART (which is permitted by
the PL011 TRM.) It's only taken about 20 years for this to happen, so
I think we should think we're lucky this hasn't come up before! :D

> > +		virq = amba_dev->irq[i];
> > +		if (virq == 0)
> > +			break;
> > +
> > +		ret = request_irq(virq, pl011_int, IRQF_SHARED, dev_name(&amba_dev->dev), uap);
> 
> Note that using dev_name() here technically breaks user ABI - scripts
> looking in /proc for an irq named "uart-pl011" will no longer find it.
> 
> Furthermore, the "dev" cookie passed to request_irq is supposed to be
> globally unique, which "uap" isn't once you start registering it multiple
> times.

There's no difference there.

First, the "private" used with request_irq() only has to be globally
unique for the interrupt number being requested. Secondly, there is
no way for two UARTs to share the same "uap" structure, and finally
there is a 1:1 model between "uap" and "dev". So, I don't see a problem
as far as whether we use "uap" or "dev" here.

> If firmware did describe all the individual PL011 IRQ outputs on a
> system where they are muxed to the same physical IRQ anyway, you'd end up
> registering ambiguous IRQ actions here. Of course in practice you might
> still get away with that, but it is technically wrong.

Yes. This would also make a total nonsense of using multiple interrupt
lines.

The whole point of using multiple interrupt lines from the UART is so
the interrupt demultiplexing can be handled at the interrupt controller
and their priorities can be decided there. If we adopt a software
structure where we effectively register our "merged" interrupt handler
for all these signals, then there is absolutely no benefit to using
multiple interrupt signals, since that will override any priority, and
we will still have the extra overhead of decoding which interrupt fired
at the UART level.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2021-08-16 10:34 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-13  3:31 [PATCH v6] arm pl011 serial: support multi-irq request Bing Fan
2021-08-13  7:19 ` Greg KH
     [not found]   ` <9c3a4336-b6c4-d96e-9a9d-8001dddcee20@gmail.com>
2021-08-13  8:17     ` Greg KH
2021-08-13 14:08       ` Robin Murphy
2021-08-13 15:04         ` Greg KH
2021-08-13 15:17           ` Robin Murphy
2021-08-13 14:37 ` Robin Murphy
     [not found]   ` <5b68f69c-f9cd-b0a4-45dd-d6db6d09fd65@gmail.com>
2021-08-16 10:19     ` Robin Murphy
2021-08-16 10:34   ` Russell King (Oracle)

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).