linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] PCI/MSI: Don't touch MSI bits when the PCI device is disconnected
@ 2018-07-30 21:21 Alexandru Gagniuc
  2018-08-29 16:59 ` Alex G.
  2018-09-12 21:28 ` Bjorn Helgaas
  0 siblings, 2 replies; 5+ messages in thread
From: Alexandru Gagniuc @ 2018-07-30 21:21 UTC (permalink / raw)
  To: linux-pci, bhelgaas
  Cc: keith.busch, alex_gagniuc, austin_bolen, shyam_iyer, Narendra_K,
	Stuart_Hayes, lukas, Alexandru Gagniuc, linux-kernel

When a PCI device is gone, we don't want to send IO to it if we can
avoid it. We expose functionality via the irq_chip structure. As
users of that structure may not know about the underlying PCI device,
it's our responsibility to guard against removed devices.

irq_write_msi_msg is already guarded. pci_msi_(un)mask_irq are not.
Guard them for completeness.

For example, surprise removal of a PCIe device triggers teardown. This
touches the irq_chips ops some point to disable the interrupts. I/O
generated here can crash the system on machines with buggy firmware.
Not triggering the IO in the first place eliminates the problem.

Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
---

There's another patch by Lukas Wunner that is needed (not yet published)
in order to fully block IO on SURPRISE!!! removal. The existing code only
sets the PCI_DEV_DISCONNECTED bit in an unreasonably narrow set of
circumstances. Lukas' patch fixes that.

However, this change is otherwise fully independent, and enjoy!

 drivers/pci/msi.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 4d88afdfc843..5f47b5cb0401 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -227,6 +227,9 @@ static void msi_set_mask_bit(struct irq_data *data, u32 flag)
 {
 	struct msi_desc *desc = irq_data_get_msi_desc(data);
 
+	if (pci_dev_is_disconnected(msi_desc_to_pci_dev(desc)))
+		return;
+
 	if (desc->msi_attrib.is_msix) {
 		msix_mask_irq(desc, flag);
 		readl(desc->mask_base);		/* Flush write to device */
-- 
2.17.1

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

* Re: [PATCH] PCI/MSI: Don't touch MSI bits when the PCI device is disconnected
  2018-07-30 21:21 [PATCH] PCI/MSI: Don't touch MSI bits when the PCI device is disconnected Alexandru Gagniuc
@ 2018-08-29 16:59 ` Alex G.
  2018-09-12 21:28 ` Bjorn Helgaas
  1 sibling, 0 replies; 5+ messages in thread
From: Alex G. @ 2018-08-29 16:59 UTC (permalink / raw)
  To: linux-pci, bhelgaas
  Cc: keith.busch, alex_gagniuc, austin_bolen, shyam_iyer, Narendra_K,
	Stuart_Hayes, lukas, linux-kernel

Should I resubmit this rebased on 4.19-rc*, or just leave this patch as is?

Alex

On 07/30/2018 04:21 PM, Alexandru Gagniuc wrote:
> When a PCI device is gone, we don't want to send IO to it if we can
> avoid it. We expose functionality via the irq_chip structure. As
> users of that structure may not know about the underlying PCI device,
> it's our responsibility to guard against removed devices.
> 
> irq_write_msi_msg is already guarded. pci_msi_(un)mask_irq are not.
> Guard them for completeness.
> 
> For example, surprise removal of a PCIe device triggers teardown. This
> touches the irq_chips ops some point to disable the interrupts. I/O
> generated here can crash the system on machines with buggy firmware.
> Not triggering the IO in the first place eliminates the problem.
> 
> Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
> ---
> 
> There's another patch by Lukas Wunner that is needed (not yet published)
> in order to fully block IO on SURPRISE!!! removal. The existing code only
> sets the PCI_DEV_DISCONNECTED bit in an unreasonably narrow set of
> circumstances. Lukas' patch fixes that.
> 
> However, this change is otherwise fully independent, and enjoy!
> 
>   drivers/pci/msi.c | 3 +++
>   1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
> index 4d88afdfc843..5f47b5cb0401 100644
> --- a/drivers/pci/msi.c
> +++ b/drivers/pci/msi.c
> @@ -227,6 +227,9 @@ static void msi_set_mask_bit(struct irq_data *data, u32 flag)
>   {
>   	struct msi_desc *desc = irq_data_get_msi_desc(data);
>   
> +	if (pci_dev_is_disconnected(msi_desc_to_pci_dev(desc)))
> +		return;
> +
>   	if (desc->msi_attrib.is_msix) {
>   		msix_mask_irq(desc, flag);
>   		readl(desc->mask_base);		/* Flush write to device */
> 

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

* Re: [PATCH] PCI/MSI: Don't touch MSI bits when the PCI device is disconnected
  2018-07-30 21:21 [PATCH] PCI/MSI: Don't touch MSI bits when the PCI device is disconnected Alexandru Gagniuc
  2018-08-29 16:59 ` Alex G.
@ 2018-09-12 21:28 ` Bjorn Helgaas
  2018-09-18 13:07   ` Alex_Gagniuc
  1 sibling, 1 reply; 5+ messages in thread
From: Bjorn Helgaas @ 2018-09-12 21:28 UTC (permalink / raw)
  To: Alexandru Gagniuc
  Cc: linux-pci, bhelgaas, keith.busch, alex_gagniuc, austin_bolen,
	shyam_iyer, Narendra_K, Stuart_Hayes, lukas, linux-kernel

On Mon, Jul 30, 2018 at 04:21:44PM -0500, Alexandru Gagniuc wrote:
> When a PCI device is gone, we don't want to send IO to it if we can
> avoid it. We expose functionality via the irq_chip structure. As
> users of that structure may not know about the underlying PCI device,
> it's our responsibility to guard against removed devices.

I'm pretty ambivalent about pci_dev_is_disconnected() in general, but
I think I'll take this, given a couple minor changelog clarifications:

> irq_write_msi_msg is already guarded. pci_msi_(un)mask_irq are not.
> Guard them for completeness.

By the irq_write_msi_msg() guard, I guess you mean this path:

  pci_msi_domain_write_msg       # irq_chip.irq_write_msi_msg
    __pci_write_msi_msg
      if (dev->current_state != PCI_D0 || pci_dev_is_disconnected(dev))
        /* don't touch */

pci_msi_(un)mask_irq() may be irq_chip.irq_mask, .irq_unmask, etc
pointers.  So these are parallel because they're all irq_chip function
pointers, but the changelog isn't (yet) parallel because it uses the
irq_chip pointer name for .irq_write_msi_msg but not for mask/unmask.

> For example, surprise removal of a PCIe device triggers teardown. This
> touches the irq_chips ops some point to disable the interrupts. I/O
> generated here can crash the system on machines with buggy firmware.
> Not triggering the IO in the first place eliminates the problem.

It doesn't eliminate the problem completely because .irq_mask() and
.irq_unmask() may be called for reasons other than surprise removal,
and if a surprise removal happens after the pci_dev_is_disconnected()
check but before the readl(), we will still generate I/O to a device
that's gone.  I'd be OK if you said it "reduces" the problem.

One reason I'm ambivalent about pci_dev_is_disconnected() is that in
cases like this, it turns a reproducible problem into a very
hard-to-reproduce problem, which reduces the likelihood that the buggy
firmware will be fixed.

Do you have information about known platforms with this buggy firmware
and the signature of the crash?  If you do, it's always nice to be
able to connect a patch with the user-visible problem it fixes.

> Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
> ---
> 
> There's another patch by Lukas Wunner that is needed (not yet published)
> in order to fully block IO on SURPRISE!!! removal. The existing code only
> sets the PCI_DEV_DISCONNECTED bit in an unreasonably narrow set of
> circumstances. Lukas' patch fixes that.
> 
> However, this change is otherwise fully independent, and enjoy!
> 
>  drivers/pci/msi.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
> index 4d88afdfc843..5f47b5cb0401 100644
> --- a/drivers/pci/msi.c
> +++ b/drivers/pci/msi.c
> @@ -227,6 +227,9 @@ static void msi_set_mask_bit(struct irq_data *data, u32 flag)
>  {
>  	struct msi_desc *desc = irq_data_get_msi_desc(data);
>  
> +	if (pci_dev_is_disconnected(msi_desc_to_pci_dev(desc)))
> +		return;
> +
>  	if (desc->msi_attrib.is_msix) {
>  		msix_mask_irq(desc, flag);
>  		readl(desc->mask_base);		/* Flush write to device */
> -- 
> 2.17.1
> 

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

* Re: [PATCH] PCI/MSI: Don't touch MSI bits when the PCI device is disconnected
  2018-09-12 21:28 ` Bjorn Helgaas
@ 2018-09-18 13:07   ` Alex_Gagniuc
  2018-09-18 13:07     ` Alex_Gagniuc
  0 siblings, 1 reply; 5+ messages in thread
From: Alex_Gagniuc @ 2018-09-18 13:07 UTC (permalink / raw)
  To: helgaas, mr.nuke.me
  Cc: linux-pci, bhelgaas, keith.busch, Austin.Bolen, Shyam.Iyer,
	Narendra.K, Stuart.Hayes, lukas, linux-kernel

On 9/12/2018 4:28 PM, Bjorn Helgaas wrote:=0A=
> On Mon, Jul 30, 2018 at 04:21:44PM -0500, Alexandru Gagniuc wrote:=0A=
>> When a PCI device is gone, we don't want to send IO to it if we can=0A=
>> avoid it. We expose functionality via the irq_chip structure. As=0A=
>> users of that structure may not know about the underlying PCI device,=0A=
>> it's our responsibility to guard against removed devices.=0A=
> =0A=
> I'm pretty ambivalent about pci_dev_is_disconnected() in general, but=0A=
> I think I'll take this, given a couple minor changelog clarifications:=0A=
> =0A=
>> irq_write_msi_msg is already guarded. pci_msi_(un)mask_irq are not.=0A=
>> Guard them for completeness.=0A=
> =0A=
> By the irq_write_msi_msg() guard, I guess you mean this path:=0A=
> =0A=
>    pci_msi_domain_write_msg       # irq_chip.irq_write_msi_msg=0A=
>      __pci_write_msi_msg=0A=
>        if (dev->current_state !=3D PCI_D0 || pci_dev_is_disconnected(dev)=
)=0A=
>          /* don't touch */=0A=
=0A=
Yes!=0A=
=0A=
> pci_msi_(un)mask_irq() may be irq_chip.irq_mask, .irq_unmask, etc=0A=
> pointers.  So these are parallel because they're all irq_chip function=0A=
> pointers, but the changelog isn't (yet) parallel because it uses the=0A=
> irq_chip pointer name for .irq_write_msi_msg but not for mask/unmask=0A=
=0A=
Good catch! I'll get this corrected.=0A=
=0A=
=0A=
>> For example, surprise removal of a PCIe device triggers teardown. This=
=0A=
>> touches the irq_chips ops some point to disable the interrupts. I/O=0A=
>> generated here can crash the system on machines with buggy firmware.=0A=
>> Not triggering the IO in the first place eliminates the problem.=0A=
> =0A=
> It doesn't eliminate the problem completely because .irq_mask() and=0A=
> .irq_unmask() may be called for reasons other than surprise removal,=0A=
> and if a surprise removal happens after the pci_dev_is_disconnected()=0A=
> check but before the readl(), we will still generate I/O to a device=0A=
> that's gone.  I'd be OK if you said it "reduces" the problem.=0A=
=0A=
That sounds reasonable.=0A=
=0A=
> One reason I'm ambivalent about pci_dev_is_disconnected() is that in=0A=
> cases like this, it turns a reproducible problem into a very=0A=
> hard-to-reproduce problem, which reduces the likelihood that the buggy=0A=
> firmware will be fixed.=0A=
=0A=
If it manages to turn this into 99.999% territory, I'll be much happier. =
=0A=
I'd love to give you an academically correct solution, but I just don't =0A=
see how, given how firmware-first philosophy is written.=0A=
=0A=
> Do you have information about known platforms with this buggy firmware=0A=
> and the signature of the crash?  If you do, it's always nice to be=0A=
> able to connect a patch with the user-visible problem it fixes.=0A=
=0A=
 From what I've heard, it won't be fixed. The number of changes needed =0A=
would require re-qualifying the firmware. I'm told that's very hard to =0A=
do on platforms that are shipping. I can reword this to say =0A=
"firmware-first" instead of "buggy" since they are mostly synonymous.=0A=
=0A=
Alex=0A=
=0A=
>> Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>=0A=
>> ---=0A=
>>=0A=
>> There's another patch by Lukas Wunner that is needed (not yet published)=
=0A=
>> in order to fully block IO on SURPRISE!!! removal. The existing code onl=
y=0A=
>> sets the PCI_DEV_DISCONNECTED bit in an unreasonably narrow set of=0A=
>> circumstances. Lukas' patch fixes that.=0A=
>>=0A=
>> However, this change is otherwise fully independent, and enjoy!=0A=
>>=0A=
>>   drivers/pci/msi.c | 3 +++=0A=
>>   1 file changed, 3 insertions(+)=0A=
>>=0A=
>> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c=0A=
>> index 4d88afdfc843..5f47b5cb0401 100644=0A=
>> --- a/drivers/pci/msi.c=0A=
>> +++ b/drivers/pci/msi.c=0A=
>> @@ -227,6 +227,9 @@ static void msi_set_mask_bit(struct irq_data *data, =
u32 flag)=0A=
>>   {=0A=
>>   	struct msi_desc *desc =3D irq_data_get_msi_desc(data);=0A=
>>   =0A=
>> +	if (pci_dev_is_disconnected(msi_desc_to_pci_dev(desc)))=0A=
>> +		return;=0A=
>> +=0A=
>>   	if (desc->msi_attrib.is_msix) {=0A=
>>   		msix_mask_irq(desc, flag);=0A=
>>   		readl(desc->mask_base);		/* Flush write to device */=0A=
>> -- =0A=
>> 2.17.1=0A=
>>=0A=
> =0A=
=0A=

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

* Re: [PATCH] PCI/MSI: Don't touch MSI bits when the PCI device is disconnected
  2018-09-18 13:07   ` Alex_Gagniuc
@ 2018-09-18 13:07     ` Alex_Gagniuc
  0 siblings, 0 replies; 5+ messages in thread
From: Alex_Gagniuc @ 2018-09-18 13:07 UTC (permalink / raw)
  To: helgaas, mr.nuke.me
  Cc: linux-pci, bhelgaas, keith.busch, Austin.Bolen, Shyam.Iyer,
	Narendra.K, Stuart.Hayes, lukas, linux-kernel

On 9/12/2018 4:28 PM, Bjorn Helgaas wrote:
> On Mon, Jul 30, 2018 at 04:21:44PM -0500, Alexandru Gagniuc wrote:
>> When a PCI device is gone, we don't want to send IO to it if we can
>> avoid it. We expose functionality via the irq_chip structure. As
>> users of that structure may not know about the underlying PCI device,
>> it's our responsibility to guard against removed devices.
> 
> I'm pretty ambivalent about pci_dev_is_disconnected() in general, but
> I think I'll take this, given a couple minor changelog clarifications:
> 
>> irq_write_msi_msg is already guarded. pci_msi_(un)mask_irq are not.
>> Guard them for completeness.
> 
> By the irq_write_msi_msg() guard, I guess you mean this path:
> 
>    pci_msi_domain_write_msg       # irq_chip.irq_write_msi_msg
>      __pci_write_msi_msg
>        if (dev->current_state != PCI_D0 || pci_dev_is_disconnected(dev))
>          /* don't touch */

Yes!

> pci_msi_(un)mask_irq() may be irq_chip.irq_mask, .irq_unmask, etc
> pointers.  So these are parallel because they're all irq_chip function
> pointers, but the changelog isn't (yet) parallel because it uses the
> irq_chip pointer name for .irq_write_msi_msg but not for mask/unmask

Good catch! I'll get this corrected.


>> For example, surprise removal of a PCIe device triggers teardown. This
>> touches the irq_chips ops some point to disable the interrupts. I/O
>> generated here can crash the system on machines with buggy firmware.
>> Not triggering the IO in the first place eliminates the problem.
> 
> It doesn't eliminate the problem completely because .irq_mask() and
> .irq_unmask() may be called for reasons other than surprise removal,
> and if a surprise removal happens after the pci_dev_is_disconnected()
> check but before the readl(), we will still generate I/O to a device
> that's gone.  I'd be OK if you said it "reduces" the problem.

That sounds reasonable.

> One reason I'm ambivalent about pci_dev_is_disconnected() is that in
> cases like this, it turns a reproducible problem into a very
> hard-to-reproduce problem, which reduces the likelihood that the buggy
> firmware will be fixed.

If it manages to turn this into 99.999% territory, I'll be much happier. 
I'd love to give you an academically correct solution, but I just don't 
see how, given how firmware-first philosophy is written.

> Do you have information about known platforms with this buggy firmware
> and the signature of the crash?  If you do, it's always nice to be
> able to connect a patch with the user-visible problem it fixes.

 From what I've heard, it won't be fixed. The number of changes needed 
would require re-qualifying the firmware. I'm told that's very hard to 
do on platforms that are shipping. I can reword this to say 
"firmware-first" instead of "buggy" since they are mostly synonymous.

Alex

>> Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
>> ---
>>
>> There's another patch by Lukas Wunner that is needed (not yet published)
>> in order to fully block IO on SURPRISE!!! removal. The existing code only
>> sets the PCI_DEV_DISCONNECTED bit in an unreasonably narrow set of
>> circumstances. Lukas' patch fixes that.
>>
>> However, this change is otherwise fully independent, and enjoy!
>>
>>   drivers/pci/msi.c | 3 +++
>>   1 file changed, 3 insertions(+)
>>
>> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
>> index 4d88afdfc843..5f47b5cb0401 100644
>> --- a/drivers/pci/msi.c
>> +++ b/drivers/pci/msi.c
>> @@ -227,6 +227,9 @@ static void msi_set_mask_bit(struct irq_data *data, u32 flag)
>>   {
>>   	struct msi_desc *desc = irq_data_get_msi_desc(data);
>>   
>> +	if (pci_dev_is_disconnected(msi_desc_to_pci_dev(desc)))
>> +		return;
>> +
>>   	if (desc->msi_attrib.is_msix) {
>>   		msix_mask_irq(desc, flag);
>>   		readl(desc->mask_base);		/* Flush write to device */
>> -- 
>> 2.17.1
>>
> 


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

end of thread, other threads:[~2018-09-18 18:40 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-30 21:21 [PATCH] PCI/MSI: Don't touch MSI bits when the PCI device is disconnected Alexandru Gagniuc
2018-08-29 16:59 ` Alex G.
2018-09-12 21:28 ` Bjorn Helgaas
2018-09-18 13:07   ` Alex_Gagniuc
2018-09-18 13:07     ` Alex_Gagniuc

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).