Re: [PATCH 02/18] Delayed x86 setup of PCI IRQs to bus scan time

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Oct 02, 2014 at 05:07:30AM +0100, matt@xxxxxxxxxxxx wrote:
> From: Matthew Minter <matt@xxxxxxxxxxxx>
> 
> 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.
> 
> Signed-off-by: Matthew Minter <matt@xxxxxxxxxxxx>
> 
> ---
>  arch/x86/include/asm/pci_x86.h |  7 ++--
>  arch/x86/kernel/x86_init.c     |  1 -
>  arch/x86/pci/acpi.c            |  5 ++-
>  arch/x86/pci/common.c          |  2 -
>  arch/x86/pci/irq.c             | 94 +++++++++++++++++++++++-------------------
>  5 files changed, 59 insertions(+), 50 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 e48b674..064457f 100644
> --- a/arch/x86/kernel/x86_init.c
> +++ b/arch/x86/kernel/x86_init.c
> @@ -81,7 +81,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/acpi.c b/arch/x86/pci/acpi.c
> index cfd1b13..2c433f4 100644
> --- a/arch/x86/pci/acpi.c
> +++ b/arch/x86/pci/acpi.c
> @@ -311,7 +311,7 @@ static acpi_status setup_resource(struct acpi_resource *acpi_res, void *data)
>  	} else if (orig_end != end) {
>  		dev_info(&info->bridge->dev,
>  			"host bridge window [%#llx-%#llx] "
> -			"([%#llx-%#llx] ignored, not CPU addressable)\n", 
> +			"([%#llx-%#llx] ignored, not CPU addressable)\n",
>  			start, orig_end, end + 1, orig_end);
>  	}
>  
> @@ -571,6 +571,9 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)

Your previous patch removed the weak implementation of pcibios_root_bridge_prepare yet
you are adding it here in the arch specific code. Again, confused on what you
were trying to achieve by removing the __weak version. Should that not have by default
setup bridge->swizzle_irq and bridge->map_irq to some sane defaults and kept into drivers/pci?

>  	struct pci_sysdata *sd = bridge->bus->sysdata;
>  
>  	ACPI_COMPANION_SET(&bridge->dev, sd->companion);
> +
> +	bridge->swizzle_irq = NULL;
> +	bridge->map_irq = pci_map_irq;
>  	return 0;
>  }
>  
> diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
> index 059a76c..d4ed0b0 100644
> --- a/arch/x86/pci/common.c
> +++ b/arch/x86/pci/common.c
> @@ -662,8 +662,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
>  	if ((err = pci_enable_resources(dev, mask)) < 0)
>  		return err;
>  
> -	if (!pci_dev_msi_enabled(dev))
> -		return pcibios_enable_irq(dev);
>  	return 0;
>  }
>  
> diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
> index eb500c2..33d323d 100644
> --- a/arch/x86/pci/irq.c
> +++ b/arch/x86/pci/irq.c
> @@ -594,9 +594,9 @@ static __init int intel_router_probe(struct irq_router *r, struct pci_dev *route
>  		return 1;
>  	}
>  
> -	if ((device >= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN && 
> -	     device <= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX) 
> -	||  (device >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN && 
> +	if ((device >= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN &&
> +	     device <= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX)
> +	||  (device >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN &&

More indentation fixes?

>  	     device <= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX)
>  	||  (device >= PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MIN &&
>  	     device <= PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MAX)
> @@ -875,9 +875,8 @@ static struct irq_info *pirq_get_info(struct pci_dev *dev)
>  	return NULL;
>  }
>  
> -static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
> +static int pcibios_lookup_irq(struct pci_dev *dev, u8 pin, int assign)
>  {
> -	u8 pin;
>  	struct irq_info *info;
>  	int i, pirq, newirq;
>  	int irq = 0;
> @@ -887,7 +886,6 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
>  	char *msg = NULL;
>  
>  	/* Find IRQ pin */
> -	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
>  	if (!pin) {
>  		dev_dbg(&dev->dev, "no interrupt pin\n");
>  		return 0;
> @@ -1017,50 +1015,45 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
>  					 irq, pci_name(dev2));
>  		}
>  	}
> -	return 1;
> +	/*
> +	 * Due to the complicated platform specific behvaiour we cannot defer

behaviour

> +	 * assigning dev->irq to the caller but will return it anyway
> +	 */

What? How is that sane?

> +	return dev->irq;

Beside the above comment, you are changing the behaviour of the function from previously
returning 0/1 depending on whether an irq has been found into returning 0/dev->irq. That
is unnecessary as you can extract the information anyway from dev, according to your
comment.

>  }
>  
> -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)
> +		irq = pcibios_lookup_irq(dev, pin, 0);
>  
> -		/*
> -		 * Still no IRQ? Try to lookup one...
> -		 */
> -		if (!dev->irq)
> -			pcibios_lookup_irq(dev, 0);
> -	}
> +	return irq;
>  }
>  
>  /*
> @@ -1161,6 +1154,13 @@ void __init pcibios_irq_init(void)
>  	}
>  }
>  
> +int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
> +{
> +	bridge->swizzle_irq = NULL;
> +	bridge->map_irq = pci_map_irq;
> +	return 0;
> +}

Like I've mentioned above, you already have a non-weak version in arch/x86/pci/acpi.c,
why do you provide a week one here?

Best regards,
Liviu

> +
>  static void pirq_penalize_isa_irq(int irq, int active)
>  {
>  	/*
> @@ -1185,12 +1185,20 @@ 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;
>  
>  	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
> -	if (pin && !pcibios_lookup_irq(dev, 1)) {
> +	if (pin && !pcibios_lookup_irq(dev, pin, 1)) {
>  		char *msg = "";
>  
>  		if (!io_apic_assign_pci_irqs && dev->irq)
> -- 
> 2.1.0
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

-- 
====================
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ¯\_(ツ)_/¯

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux