All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
To: Bjorn Helgaas <helgaas@kernel.org>
Cc: Matthew Minter <matt@masarand.com>,
	linux-pci@vger.kernel.org, bhelgaas@google.com,
	Liviu.Dudau@arm.com, ddaney@caviumnetworks.com,
	Thomas Gleixner <tglx@linutronix.de>
Subject: Re: [PATCH V4 08/29] x86/pci: Defer IRQ assignment to device enable time
Date: Tue, 12 Jan 2016 11:25:48 +0000	[thread overview]
Message-ID: <20160112112548.GB3601@red-moon> (raw)
In-Reply-To: <20151223230433.GA27708@localhost>

Hi Bjorn,

On Wed, Dec 23, 2015 at 05:04:33PM -0600, Bjorn Helgaas wrote:
> [+cc Thomas]
> 
> Hi Matthew,
> 
> On Fri, Oct 23, 2015 at 06:03:41AM +0100, Matthew Minter wrote:
> > The x86 architecture boot code currently traverses the PCI buses with
> > an extra pass in order to initialise the PCI device IRQs at boot, this
> > patch avoids this pass and defers the IRQ assignment untill device
> > enable time which also has the benefit that hot-plugged devices are
> > assigned IRQs without additional code.
> 
> I think the outline of this patch (doing the IRQ init at device
> enable-time instead of at boot-time) is good, but I am concerned about
> two things:
> 
> 1) pcibios_lookup_irq() contains a for_each_pci_dev() loop that
> updates dev->irq for all devices with the same pirq value.  Previously
> we ran that loop at boot-time via this path:
> 
>   pci_subsys_init                   # subsys_initcall
>     x86_init.pci.init_irq           # .init_irq = x86_default_pci_init_irq
>     x86_default_pci_init_irq        # x86_default_pci_init_irq = pcibios_irq_init
>     pcibios_irq_init
>       x86_init.pci.fixup_irqs       # .fixup_irqs = x86_default_pci_fixup_irqs
>       x86_default_pci_fixup_irqs    # x86_default_pci_fixup_irqs = pcibios_fixup_irqs
>       pcibios_fixup_irqs
>         for_each_pci_dev
>           pcibios_lookup_irq
> 
> Now we'll run it later, in this path:
> 
>   pci_enable_device
>     pci_enable_device_flags
>       do_pci_enable_device
>         pci_assign_irq
>           pci_map_irq                   # bridge->map_irq
>             pcibios_fixup_irq
>               pcibios_lookup_irq
>                 for_each_pci_dev(dev2)
>                   dev2->irq = irq       # <-- potential problem
> 
> The problem is that dev2 is an unrelated device and may already have a
> driver bound to it, and we shouldn't change dev->irq after a driver
> binds to a device.

Yes, this looks wrong. On the other hand, removing pci_fixup_irqs from
generic PCI code does not mean that we cannot implement it in x86 using
pci_assign_irq() (in arch code) and leave the current behaviour unchanged.

True, do_pci_enable_device() (or better pci_device_probe() as you say
below) would carry out the fixup unconditionally, but if arch code
carries out the fixup before do_pci_enable_device() I *guess* that the
one carried out in do_pci_enable_device() would become a nop (the fixup
already assigned an IRQ so basically doing it again in do_pci_enable_device()
should not change anything. Still, I am not a fan of this solution either).

I would avoid holding this patch series back, it is a nice clean-up.

> I don't know enough about interrupts and PIRQ to know whether this is
> really a problem in practice or not.  I added Thomas in case he knows.
> 
> 2) I'm also worried about the fact that we don't do the IRQ init until
> a driver calls pci_enable_device().  We've been doing some IRQ init in
> pcibios_alloc_irq() in this path for a long time:
> 
>   pci_subsys_init
>     ...
>       pcibios_fixup_irqs                # <-- moved from here ...
>         for_each_pci_dev
>   ...
>   pci_device_probe
>     pcibios_alloc_irq
>       pcibios_enable_irq                # pcibios_enable_irq = acpi_pci_irq_enable
>                                         # (or pirq_enable_irq, x86_of_pci_irq_enable, lguest_enable_irq, etc)
>       acpi_pci_irq_enable
>     __pci_device_probe
>       ...
> 	pci_drv->probe                  # driver .probe routine
> 	  ...
> 	    pci_enable_device
>               ...
>                 pci_fixup_irq           # <-- ... to here
> 
> I think there are two problems here:
> 
> 2.1) We changed the order of pcibios_enable_irq() and pci_fixup_irq().
> Both update dev->irq, and I doubt it's safe to reverse the order.
> 
> 2.2) It's conceivable that a driver may use interrupts without ever
> calling pci_enable_device().  That driver would be broken by this
> change.
> 
> I think we could probably fix both of these worries by calling
> pci_assign_irq() from pci_device_probe() instead of from
> do_pci_enable_device().

Yes, I think your proposal makes sense (we can even add it to
pci_device_add() (?), the pointers in the bridge used to carry out the
mapping, set-up in pci_create_root_bus()->pcibios_root_bridge_prepare()
are already set-up by the time that function is called).

Actually, executing pci_assign_irq() in pci_device_add(), would not
it solve the issue above too ? Certainly we would still have an issue
with hot-added devices (I have no idea how this works at present
on x86).

We have to decide if the assignment can be done in generic code or
in pcibios_* arches callbacks (to do it on a per-arch basis).

> I'm not so sure about the pcibios_lookup_irq() problem.  That's a
> little farther outside my area, so I'll have to look at that some
> more.
> 
> I really want to merge this stuff because it's a major cleanup, so I'm
> going to push on this more myself.  I'm just writing this as a
> heads-up in case anybody else has ideas.

+1, I am reviewing the ARM/ARM64 code to check for correctness.

Thanks,
Lorenzo

> 
> Bjorn
> 
> > Signed-off-by: Matthew Minter <matt@masarand.com>
> > ---
> >  arch/x86/include/asm/pci_x86.h |  7 +++--
> >  arch/x86/kernel/x86_init.c     |  1 -
> >  arch/x86/pci/irq.c             | 70 +++++++++++++++++++++---------------------
> >  3 files changed, 39 insertions(+), 39 deletions(-)
> > 
> > diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
> > index fa1195d..16fd8e9 100644
> > --- a/arch/x86/include/asm/pci_x86.h
> > +++ b/arch/x86/include/asm/pci_x86.h
> > @@ -90,6 +90,7 @@ extern unsigned int pcibios_irq_mask;
> >  
> >  extern raw_spinlock_t pci_config_lock;
> >  
> > +extern int pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin);
> >  extern int (*pcibios_enable_irq)(struct pci_dev *dev);
> >  extern void (*pcibios_disable_irq)(struct pci_dev *dev);
> >  
> > @@ -119,7 +120,7 @@ extern int __init pci_acpi_init(void);
> >  extern void __init pcibios_irq_init(void);
> >  extern int __init pcibios_init(void);
> >  extern int pci_legacy_init(void);
> > -extern void pcibios_fixup_irqs(void);
> > +extern int pcibios_fixup_irq(struct pci_dev *dev, u8 pin);
> >  
> >  /* pci-mmconfig.c */
> >  
> > @@ -200,9 +201,9 @@ static inline void mmio_config_writel(void __iomem *pos, u32 val)
> >  #  define x86_default_pci_init		pci_legacy_init
> >  # endif
> >  # define x86_default_pci_init_irq	pcibios_irq_init
> > -# define x86_default_pci_fixup_irqs	pcibios_fixup_irqs
> > +# define x86_default_pci_fixup_irq	pcibios_fixup_irq
> >  #else
> >  # define x86_default_pci_init		NULL
> >  # define x86_default_pci_init_irq	NULL
> > -# define x86_default_pci_fixup_irqs	NULL
> > +# define x86_default_pci_fixup_irq	NULL
> >  #endif
> > diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
> > index 3839628..810f1dd 100644
> > --- a/arch/x86/kernel/x86_init.c
> > +++ b/arch/x86/kernel/x86_init.c
> > @@ -80,7 +80,6 @@ struct x86_init_ops x86_init __initdata = {
> >  	.pci = {
> >  		.init			= x86_default_pci_init,
> >  		.init_irq		= x86_default_pci_init_irq,
> > -		.fixup_irqs		= x86_default_pci_fixup_irqs,
> >  	},
> >  };
> >  
> > diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
> > index 350e785..15c507b 100644
> > --- a/arch/x86/pci/irq.c
> > +++ b/arch/x86/pci/irq.c
> > @@ -1021,47 +1021,38 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
> >  	return 1;
> >  }
> >  
> > -void __init pcibios_fixup_irqs(void)
> > +int pcibios_fixup_irq(struct pci_dev *dev, u8 pin)
> >  {
> > -	struct pci_dev *dev = NULL;
> > -	u8 pin;
> > -
> > +	int irq = dev->irq;
> >  	DBG(KERN_DEBUG "PCI: IRQ fixup\n");
> > -	for_each_pci_dev(dev) {
> > -		/*
> > -		 * If the BIOS has set an out of range IRQ number, just
> > -		 * ignore it.  Also keep track of which IRQ's are
> > -		 * already in use.
> > -		 */
> > -		if (dev->irq >= 16) {
> > -			dev_dbg(&dev->dev, "ignoring bogus IRQ %d\n", dev->irq);
> > -			dev->irq = 0;
> > -		}
> > -		/*
> > -		 * If the IRQ is already assigned to a PCI device,
> > -		 * ignore its ISA use penalty
> > -		 */
> > -		if (pirq_penalty[dev->irq] >= 100 &&
> > -				pirq_penalty[dev->irq] < 100000)
> > -			pirq_penalty[dev->irq] = 0;
> > -		pirq_penalty[dev->irq]++;
> > +	/*
> > +	 * If the BIOS has set an out of range IRQ number, just
> > +	 * ignore it.  Also keep track of which IRQ's are
> > +	 * already in use.
> > +	 */
> > +	if (irq >= 16) {
> > +		dev_dbg(&dev->dev, "ignoring bogus IRQ %d\n", irq);
> > +		irq = 0;
> >  	}
> > +	/*
> > +	 * If the IRQ is already assigned to a PCI device,
> > +	 * ignore its ISA use penalty
> > +	 */
> > +	if (pirq_penalty[irq] >= 100 &&
> > +			pirq_penalty[irq] < 100000)
> > +		pirq_penalty[irq] = 0;
> > +	pirq_penalty[irq]++;
> >  
> > -	if (io_apic_assign_pci_irqs)
> > -		return;
> > +	if (io_apic_assign_pci_irqs || !pin)
> > +		return irq;
> >  
> > -	dev = NULL;
> > -	for_each_pci_dev(dev) {
> > -		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
> > -		if (!pin)
> > -			continue;
> > +	/*
> > +	 * Still no IRQ? Try to lookup one...
> > +	 */
> > +	if (!irq && pcibios_lookup_irq(dev, 0))
> > +		irq = dev->irq;
> >  
> > -		/*
> > -		 * Still no IRQ? Try to lookup one...
> > -		 */
> > -		if (!dev->irq)
> > -			pcibios_lookup_irq(dev, 0);
> > -	}
> > +	return irq;
> >  }
> >  
> >  /*
> > @@ -1174,6 +1165,7 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
> >  		struct pci_sysdata *sd = bridge->bus->sysdata;
> >  		ACPI_COMPANION_SET(&bridge->dev, sd->companion);
> >  	}
> > +	bridge->map_irq = pci_map_irq;
> >  	return 0;
> >  }
> >  
> > @@ -1201,6 +1193,14 @@ void pcibios_penalize_isa_irq(int irq, int active)
> >  		pirq_penalize_isa_irq(irq, active);
> >  }
> >  
> > +int pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
> > +{
> > +	dev->irq = pcibios_fixup_irq(dev, pin);
> > +	if (pcibios_enable_irq(dev))
> > +		return -1;
> > +	return dev->irq;
> > +}
> > +
> >  static int pirq_enable_irq(struct pci_dev *dev)
> >  {
> >  	u8 pin = 0;
> > -- 
> > 2.6.2
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

  reply	other threads:[~2016-01-12 11:24 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-10-23  5:03 [PATCH V4] Delay allocation of PCI device IRQs from boot time until bus scan time to fix PCI hotplugging Matthew Minter
2015-10-23  5:03 ` [PATCH V4 01/29] PCI: Build setup-irq.o on all arches Matthew Minter
2015-10-23  5:03 ` [PATCH V4 02/29] PCI: Add a prototype for pci_find_host_bridge to pci.h Matthew Minter
2015-10-23  5:03 ` [PATCH V4 03/29] PCI: Add IRQ mapping function pointers to pci_host_bridge struct Matthew Minter
2015-10-23  5:03 ` [PATCH V4 04/29] PCI: Remove const from the pci_dev struct passed to pci_fixup_irqs Matthew Minter
2015-10-23  5:03 ` [PATCH V4 05/29] PCI: Add pci_assign_irq function and have pci_fixup_irqs use it Matthew Minter
2015-10-23  5:03 ` [PATCH V4 06/29] PCI: Add a call to pci_assign_irq in do_pci_enable_device Matthew Minter
2015-10-23  5:03 ` [PATCH V4 07/29] x86/pci: Move pcibios_root_bridge_prepare from acpi.c to irq.c Matthew Minter
2015-10-23  5:03 ` [PATCH V4 08/29] x86/pci: Defer IRQ assignment to device enable time Matthew Minter
2015-12-23 23:04   ` Bjorn Helgaas
2016-01-12 11:25     ` Lorenzo Pieralisi [this message]
2015-10-23  5:03 ` [PATCH V4 09/29] x86/pci: Pass pin into pcibios_lookup_irq rather than look it up Matthew Minter
2015-10-23  5:03 ` [PATCH V4 10/29] ARM/PCI: Defer IRQ assignment to device enable time Matthew Minter
2015-10-23  5:03 ` [PATCH V4 11/29] powerpc/pci: " Matthew Minter
2015-10-23  5:03 ` [PATCH V4 12/29] sh/PCI: Remove __init optimisations from IRQ mapping functions/data Matthew Minter
2015-10-23  5:03 ` [PATCH V4 13/29] sh/PCI: Defer IRQ assignment to device enable time Matthew Minter
2015-10-23  5:03 ` [PATCH V4 14/29] alpha/PCI: " Matthew Minter
2015-10-23  5:03 ` [PATCH V4 15/29] cris/PCI: " Matthew Minter
2015-10-23  5:03 ` [PATCH V4 16/29] frv/PCI: " Matthew Minter
2015-10-23  5:03 ` [PATCH V4 17/29] m68k/pci: " Matthew Minter
2015-10-23  5:44   ` kbuild test robot
2015-10-23  5:03 ` [PATCH V4 18/29] microblaze/PCI: " Matthew Minter
2015-10-23  5:40   ` kbuild test robot
2015-10-23  5:03 ` [PATCH V4 19/29] MIPS/PCI: " Matthew Minter
2015-10-23  6:02   ` kbuild test robot
2015-10-23  5:03 ` [PATCH V4 20/29] mn10300: Defer PCI " Matthew Minter
2015-10-23  5:03 ` [PATCH V4 21/29] mn10300: Remove pcibios_enable_device function Matthew Minter
2015-10-23  5:03 ` [PATCH V4 22/29] sparc/PCI: Defer IRQ assignment to device enable time Matthew Minter
2015-10-23  5:03 ` [PATCH V4 23/29] tile: pci: " Matthew Minter
2015-10-23  5:34   ` kbuild test robot
2015-10-23  5:03 ` [PATCH V4 24/29] unicore32/PCI: " Matthew Minter
2015-10-23  5:03 ` [PATCH V4 25/29] PCI: Update pci-versatile to use IRQ deferred assignment Matthew Minter
2015-10-23  5:03 ` [PATCH V4 26/29] PCI: Update pcie-iproc to use IRQ deffered assignment Matthew Minter
2015-10-23  5:04 ` [PATCH V4 27/29] PCI: Update pci-host-generic " Matthew Minter
2015-10-23  9:40   ` kbuild test robot
2015-10-23  5:04 ` [PATCH V4 28/29] of/pci: Fix comment for pci_fixup_irqs changing to pci_assign_irq Matthew Minter
2016-01-13 11:25   ` Lorenzo Pieralisi
2015-10-23  5:04 ` [PATCH V4 29/29] PCI: Remove pci_fixup_irqs function Matthew Minter
2015-12-07 17:32 ` [PATCH V4] Delay allocation of PCI device IRQs from boot time until bus scan time to fix PCI hotplugging Bjorn Helgaas
2015-12-18 21:54   ` Christopher Covington
2015-12-19 11:50     ` Matthew Minter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160112112548.GB3601@red-moon \
    --to=lorenzo.pieralisi@arm.com \
    --cc=Liviu.Dudau@arm.com \
    --cc=bhelgaas@google.com \
    --cc=ddaney@caviumnetworks.com \
    --cc=helgaas@kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=matt@masarand.com \
    --cc=tglx@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.