diff mbox

[v3,04/27] arm/MSI: Save MSI chip in pci_sys_data

Message ID 1413342435-7876-5-git-send-email-wangyijing@huawei.com (mailing list archive)
State New, archived
Delegated to: Bjorn Helgaas
Headers show

Commit Message

Yijing Wang Oct. 15, 2014, 3:06 a.m. UTC
Saving msi chip in pci_sys_data can make pci bus and
devices don't need to know msi chip detail, it also
make pci enumeration code be decoupled from msi chip.
In fact, all pci devices under the same pci hostbridge
share same msi chip. So msi chip should be seen as one
of resources or attributes to be initialized in pci host
bridge driver. Currently, pci hostbridge drivers create
pci_host_bridge in pci_create_root_bus(), and pass arch
specific pci sysdata to core pci scan functions. So pci
arch sysdata is good place to save msi chip.

Signed-off-by: Yijing Wang <wangyijing@huawei.com>
---
 arch/arm/include/asm/mach/pci.h |    6 ++++++
 arch/arm/include/asm/pci.h      |    9 +++++++++
 arch/arm/kernel/bios32.c        |    3 +++
 drivers/pci/msi.c               |    6 ++++++
 include/linux/pci.h             |    9 +++++++++
 5 files changed, 33 insertions(+), 0 deletions(-)

Comments

Lorenzo Pieralisi Oct. 20, 2014, 5:21 p.m. UTC | #1
On Wed, Oct 15, 2014 at 04:06:52AM +0100, Yijing Wang wrote:
> Saving msi chip in pci_sys_data can make pci bus and
> devices don't need to know msi chip detail, it also
> make pci enumeration code be decoupled from msi chip.
> In fact, all pci devices under the same pci hostbridge
> share same msi chip. So msi chip should be seen as one
> of resources or attributes to be initialized in pci host
> bridge driver. Currently, pci hostbridge drivers create
> pci_host_bridge in pci_create_root_bus(), and pass arch
> specific pci sysdata to core pci scan functions. So pci
> arch sysdata is good place to save msi chip.
> 
> Signed-off-by: Yijing Wang <wangyijing@huawei.com>
> ---
>  arch/arm/include/asm/mach/pci.h |    6 ++++++
>  arch/arm/include/asm/pci.h      |    9 +++++++++
>  arch/arm/kernel/bios32.c        |    3 +++
>  drivers/pci/msi.c               |    6 ++++++
>  include/linux/pci.h             |    9 +++++++++
>  5 files changed, 33 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/include/asm/mach/pci.h b/arch/arm/include/asm/mach/pci.h
> index 7fc4278..59b0d87 100644
> --- a/arch/arm/include/asm/mach/pci.h
> +++ b/arch/arm/include/asm/mach/pci.h
> @@ -22,6 +22,9 @@ struct hw_pci {
>  #ifdef CONFIG_PCI_DOMAINS
>  	int		domain;
>  #endif
> +#ifdef CONFIG_PCI_MSI
> +	struct msi_chip *msi_chip;
> +#endif
>  	struct pci_ops	*ops;
>  	int		nr_controllers;
>  	void		**private_data;
> @@ -47,6 +50,9 @@ struct pci_sys_data {
>  #ifdef CONFIG_PCI_DOMAINS
>  	int		domain;
>  #endif
> +#ifdef CONFIG_PCI_MSI
> +	struct msi_chip *msi_chip;
> +#endif

This struct is defined for ARM only. We are trying to remove dependency on it
so that we can have a single driver for ARM32 and ARM64 systems without
pcibios dependency. Why can't we add this msi chip data to the host
bridge struct instead ? I understand it is all a matter of how to pass
the pointer to pci_scan_root_bus(), where the bridge is created.
We could initialize the msi chip on the bridge through the bus pointer
returned by the pci_scan_root_bus() function.

Thanks,
Lorenzo

>  	struct list_head node;
>  	int		busnr;		/* primary bus number			*/
>  	u64		mem_offset;	/* bus->cpu memory mapping offset	*/
> diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h
> index 7e95d85..b562c09 100644
> --- a/arch/arm/include/asm/pci.h
> +++ b/arch/arm/include/asm/pci.h
> @@ -31,6 +31,15 @@ static inline int pci_proc_domain(struct pci_bus *bus)
>  }
>  #endif /* CONFIG_PCI_DOMAINS */
>  
> +#ifdef CONFIG_PCI_MSI
> +static inline struct msi_chip *pci_msi_chip(struct pci_bus *bus)
> +{
> +	struct pci_sys_data *root = bus->sysdata;
> +
> +	return root->msi_chip;
> +}
> +#endif
> +
>  /*
>   * The PCI address space does equal the physical memory address space.
>   * The networking and block device layers use this boolean for bounce
> diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
> index 17a26c1..a19038d 100644
> --- a/arch/arm/kernel/bios32.c
> +++ b/arch/arm/kernel/bios32.c
> @@ -471,6 +471,9 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
>  #ifdef CONFIG_PCI_DOMAINS
>  		sys->domain  = hw->domain;
>  #endif
> +#ifdef CONFIG_PCI_MSI
> +		sys->msi_chip = hw->msi_chip;
> +#endif
>  		sys->busnr   = busnr;
>  		sys->swizzle = hw->swizzle;
>  		sys->map_irq = hw->map_irq;
> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
> index 22e413c..f11108c 100644
> --- a/drivers/pci/msi.c
> +++ b/drivers/pci/msi.c
> @@ -35,6 +35,9 @@ int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
>  	struct msi_chip *chip = dev->bus->msi;
>  	int err;
>  
> +	if (!chip)
> +		chip = pci_msi_chip(dev->bus);
> +
>  	if (!chip || !chip->setup_irq)
>  		return -EINVAL;
>  
> @@ -50,6 +53,9 @@ void __weak arch_teardown_msi_irq(unsigned int irq)
>  	struct msi_desc *entry = irq_get_msi_desc(irq);
>  	struct msi_chip *chip = entry->dev->bus->msi;
>  
> +	if (!chip)
> +		chip = pci_msi_chip(entry->dev->bus);
> +
>  	if (!chip || !chip->teardown_irq)
>  		return;
>  
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 9cd2721..7a48b40 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1433,6 +1433,15 @@ static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
>  
>  #include <asm/pci.h>
>  
> +/* Just avoid compile error, will be clean up later */
> +#ifdef CONFIG_PCI_MSI
> +
> +#ifndef pci_msi_chip
> +#define pci_msi_chip(bus)	NULL
> +#endif
> +
> +#endif
> +
>  /* these helpers provide future and backwards compatibility
>   * for accessing popular PCI BAR info */
>  #define pci_resource_start(dev, bar)	((dev)->resource[(bar)].start)
> -- 
> 1.7.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 

--
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
Yijing Wang Oct. 21, 2014, 1:32 a.m. UTC | #2
On 2014/10/21 1:21, Lorenzo Pieralisi wrote:
> On Wed, Oct 15, 2014 at 04:06:52AM +0100, Yijing Wang wrote:
>> Saving msi chip in pci_sys_data can make pci bus and
>> devices don't need to know msi chip detail, it also
>> make pci enumeration code be decoupled from msi chip.
>> In fact, all pci devices under the same pci hostbridge
>> share same msi chip. So msi chip should be seen as one
>> of resources or attributes to be initialized in pci host
>> bridge driver. Currently, pci hostbridge drivers create
>> pci_host_bridge in pci_create_root_bus(), and pass arch
>> specific pci sysdata to core pci scan functions. So pci
>> arch sysdata is good place to save msi chip.
>>
>> Signed-off-by: Yijing Wang <wangyijing@huawei.com>
>> ---
>>  arch/arm/include/asm/mach/pci.h |    6 ++++++
>>  arch/arm/include/asm/pci.h      |    9 +++++++++
>>  arch/arm/kernel/bios32.c        |    3 +++
>>  drivers/pci/msi.c               |    6 ++++++
>>  include/linux/pci.h             |    9 +++++++++
>>  5 files changed, 33 insertions(+), 0 deletions(-)
>>
>> diff --git a/arch/arm/include/asm/mach/pci.h b/arch/arm/include/asm/mach/pci.h
>> index 7fc4278..59b0d87 100644
>> --- a/arch/arm/include/asm/mach/pci.h
>> +++ b/arch/arm/include/asm/mach/pci.h
>> @@ -22,6 +22,9 @@ struct hw_pci {
>>  #ifdef CONFIG_PCI_DOMAINS
>>  	int		domain;
>>  #endif
>> +#ifdef CONFIG_PCI_MSI
>> +	struct msi_chip *msi_chip;
>> +#endif
>>  	struct pci_ops	*ops;
>>  	int		nr_controllers;
>>  	void		**private_data;
>> @@ -47,6 +50,9 @@ struct pci_sys_data {
>>  #ifdef CONFIG_PCI_DOMAINS
>>  	int		domain;
>>  #endif
>> +#ifdef CONFIG_PCI_MSI
>> +	struct msi_chip *msi_chip;
>> +#endif
> 
> This struct is defined for ARM only. We are trying to remove dependency on it
> so that we can have a single driver for ARM32 and ARM64 systems without
> pcibios dependency. Why can't we add this msi chip data to the host
> bridge struct instead ? I understand it is all a matter of how to pass
> the pointer to pci_scan_root_bus(), where the bridge is created.
> We could initialize the msi chip on the bridge through the bus pointer
> returned by the pci_scan_root_bus() function.

As mentioned in Patch 0, I will refactor generic pci hostbridge in another series,
We need not only save msi_chip into pci_host_bridge, and other common info, like domain_nr,
resources.

Thanks!
Yijing.

> 
> Thanks,
> Lorenzo
> 
>>  	struct list_head node;
>>  	int		busnr;		/* primary bus number			*/
>>  	u64		mem_offset;	/* bus->cpu memory mapping offset	*/
>> diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h
>> index 7e95d85..b562c09 100644
>> --- a/arch/arm/include/asm/pci.h
>> +++ b/arch/arm/include/asm/pci.h
>> @@ -31,6 +31,15 @@ static inline int pci_proc_domain(struct pci_bus *bus)
>>  }
>>  #endif /* CONFIG_PCI_DOMAINS */
>>  
>> +#ifdef CONFIG_PCI_MSI
>> +static inline struct msi_chip *pci_msi_chip(struct pci_bus *bus)
>> +{
>> +	struct pci_sys_data *root = bus->sysdata;
>> +
>> +	return root->msi_chip;
>> +}
>> +#endif
>> +
>>  /*
>>   * The PCI address space does equal the physical memory address space.
>>   * The networking and block device layers use this boolean for bounce
>> diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
>> index 17a26c1..a19038d 100644
>> --- a/arch/arm/kernel/bios32.c
>> +++ b/arch/arm/kernel/bios32.c
>> @@ -471,6 +471,9 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
>>  #ifdef CONFIG_PCI_DOMAINS
>>  		sys->domain  = hw->domain;
>>  #endif
>> +#ifdef CONFIG_PCI_MSI
>> +		sys->msi_chip = hw->msi_chip;
>> +#endif
>>  		sys->busnr   = busnr;
>>  		sys->swizzle = hw->swizzle;
>>  		sys->map_irq = hw->map_irq;
>> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
>> index 22e413c..f11108c 100644
>> --- a/drivers/pci/msi.c
>> +++ b/drivers/pci/msi.c
>> @@ -35,6 +35,9 @@ int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
>>  	struct msi_chip *chip = dev->bus->msi;
>>  	int err;
>>  
>> +	if (!chip)
>> +		chip = pci_msi_chip(dev->bus);
>> +
>>  	if (!chip || !chip->setup_irq)
>>  		return -EINVAL;
>>  
>> @@ -50,6 +53,9 @@ void __weak arch_teardown_msi_irq(unsigned int irq)
>>  	struct msi_desc *entry = irq_get_msi_desc(irq);
>>  	struct msi_chip *chip = entry->dev->bus->msi;
>>  
>> +	if (!chip)
>> +		chip = pci_msi_chip(entry->dev->bus);
>> +
>>  	if (!chip || !chip->teardown_irq)
>>  		return;
>>  
>> diff --git a/include/linux/pci.h b/include/linux/pci.h
>> index 9cd2721..7a48b40 100644
>> --- a/include/linux/pci.h
>> +++ b/include/linux/pci.h
>> @@ -1433,6 +1433,15 @@ static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
>>  
>>  #include <asm/pci.h>
>>  
>> +/* Just avoid compile error, will be clean up later */
>> +#ifdef CONFIG_PCI_MSI
>> +
>> +#ifndef pci_msi_chip
>> +#define pci_msi_chip(bus)	NULL
>> +#endif
>> +
>> +#endif
>> +
>>  /* these helpers provide future and backwards compatibility
>>   * for accessing popular PCI BAR info */
>>  #define pci_resource_start(dev, bar)	((dev)->resource[(bar)].start)
>> -- 
>> 1.7.1
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at  http://www.tux.org/lkml/
>>
> 
> 
> .
>
Bjorn Helgaas Oct. 23, 2014, 5:35 a.m. UTC | #3
On Wed, Oct 15, 2014 at 11:06:52AM +0800, Yijing Wang wrote:
> Saving msi chip in pci_sys_data can make pci bus and
> devices don't need to know msi chip detail, it also
> make pci enumeration code be decoupled from msi chip.
> In fact, all pci devices under the same pci hostbridge
> share same msi chip. So msi chip should be seen as one
> of resources or attributes to be initialized in pci host
> bridge driver. Currently, pci hostbridge drivers create
> pci_host_bridge in pci_create_root_bus(), and pass arch
> specific pci sysdata to core pci scan functions. So pci
> arch sysdata is good place to save msi chip.
> 
> Signed-off-by: Yijing Wang <wangyijing@huawei.com>
> ---
>  arch/arm/include/asm/mach/pci.h |    6 ++++++
>  arch/arm/include/asm/pci.h      |    9 +++++++++
>  arch/arm/kernel/bios32.c        |    3 +++
>  drivers/pci/msi.c               |    6 ++++++
>  include/linux/pci.h             |    9 +++++++++
>  5 files changed, 33 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/include/asm/mach/pci.h b/arch/arm/include/asm/mach/pci.h
> index 7fc4278..59b0d87 100644
> --- a/arch/arm/include/asm/mach/pci.h
> +++ b/arch/arm/include/asm/mach/pci.h
> @@ -22,6 +22,9 @@ struct hw_pci {
>  #ifdef CONFIG_PCI_DOMAINS
>  	int		domain;
>  #endif
> +#ifdef CONFIG_PCI_MSI
> +	struct msi_chip *msi_chip;
> +#endif
>  	struct pci_ops	*ops;
>  	int		nr_controllers;
>  	void		**private_data;
> @@ -47,6 +50,9 @@ struct pci_sys_data {
>  #ifdef CONFIG_PCI_DOMAINS
>  	int		domain;
>  #endif
> +#ifdef CONFIG_PCI_MSI
> +	struct msi_chip *msi_chip;
> +#endif
>  	struct list_head node;
>  	int		busnr;		/* primary bus number			*/
>  	u64		mem_offset;	/* bus->cpu memory mapping offset	*/
> diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h
> index 7e95d85..b562c09 100644
> --- a/arch/arm/include/asm/pci.h
> +++ b/arch/arm/include/asm/pci.h
> @@ -31,6 +31,15 @@ static inline int pci_proc_domain(struct pci_bus *bus)
>  }
>  #endif /* CONFIG_PCI_DOMAINS */
>  
> +#ifdef CONFIG_PCI_MSI
> +static inline struct msi_chip *pci_msi_chip(struct pci_bus *bus)
> +{
> +	struct pci_sys_data *root = bus->sysdata;
> +
> +	return root->msi_chip;
> +}
> +#endif
> +
>  /*
>   * The PCI address space does equal the physical memory address space.
>   * The networking and block device layers use this boolean for bounce
> diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
> index 17a26c1..a19038d 100644
> --- a/arch/arm/kernel/bios32.c
> +++ b/arch/arm/kernel/bios32.c
> @@ -471,6 +471,9 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
>  #ifdef CONFIG_PCI_DOMAINS
>  		sys->domain  = hw->domain;
>  #endif
> +#ifdef CONFIG_PCI_MSI
> +		sys->msi_chip = hw->msi_chip;
> +#endif
>  		sys->busnr   = busnr;
>  		sys->swizzle = hw->swizzle;
>  		sys->map_irq = hw->map_irq;
> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
> index 22e413c..f11108c 100644
> --- a/drivers/pci/msi.c
> +++ b/drivers/pci/msi.c
> @@ -35,6 +35,9 @@ int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
>  	struct msi_chip *chip = dev->bus->msi;
>  	int err;
>  
> +	if (!chip)
> +		chip = pci_msi_chip(dev->bus);
> +
>  	if (!chip || !chip->setup_irq)
>  		return -EINVAL;
>  
> @@ -50,6 +53,9 @@ void __weak arch_teardown_msi_irq(unsigned int irq)
>  	struct msi_desc *entry = irq_get_msi_desc(irq);
>  	struct msi_chip *chip = entry->dev->bus->msi;
>  
> +	if (!chip)
> +		chip = pci_msi_chip(entry->dev->bus);
> +
>  	if (!chip || !chip->teardown_irq)
>  		return;
>  
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 9cd2721..7a48b40 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1433,6 +1433,15 @@ static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
>  
>  #include <asm/pci.h>
>  
> +/* Just avoid compile error, will be clean up later */
> +#ifdef CONFIG_PCI_MSI
> +
> +#ifndef pci_msi_chip
> +#define pci_msi_chip(bus)	NULL
> +#endif
> +#endif

I don't like the mixture of ARM changes and PCI core changes in the same
patch.  Can you split this into a core patch that does something like this:

  struct msi_chip * __weak pcibios_msi_controller(struct pci_bus *bus)
  {
    return NULL;
  }

  struct msi_chip *pci_msi_controller(struct pci_bus *bus)
  {
    msi_chip *controller = bus->msi;

    if (controller)
      return controller;
    return pcibios_msi_controller(bus);
  }

followed by an ARM patch that puts the msi_chip pointer in struct hw_pci
and implements pcibios_msi_controller()?

I know you're trying to *remove* weak functions, and this adds one, but
this section of the series is more about getting rid of the ARM
pcibios_add_bus() because all it was used for was setting the bus->msi
pointer.

Eventually we might have a way to stash an MSI controller pointer in the
generic pci_host_bridge struct, and then the pcibios_msi_controller()
interface could go away.

> +
>  /* these helpers provide future and backwards compatibility
>   * for accessing popular PCI BAR info */
>  #define pci_resource_start(dev, bar)	((dev)->resource[(bar)].start)
> -- 
> 1.7.1
> 
--
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
Yijing Wang Oct. 23, 2014, 6:32 a.m. UTC | #4
>> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
>> index 22e413c..f11108c 100644
>> --- a/drivers/pci/msi.c
>> +++ b/drivers/pci/msi.c
>> @@ -35,6 +35,9 @@ int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
>>  	struct msi_chip *chip = dev->bus->msi;
>>  	int err;
>>  
>> +	if (!chip)
>> +		chip = pci_msi_chip(dev->bus);
>> +
>>  	if (!chip || !chip->setup_irq)
>>  		return -EINVAL;
>>  
>> @@ -50,6 +53,9 @@ void __weak arch_teardown_msi_irq(unsigned int irq)
>>  	struct msi_desc *entry = irq_get_msi_desc(irq);
>>  	struct msi_chip *chip = entry->dev->bus->msi;
>>  
>> +	if (!chip)
>> +		chip = pci_msi_chip(entry->dev->bus);
>> +
>>  	if (!chip || !chip->teardown_irq)
>>  		return;
>>  
>> diff --git a/include/linux/pci.h b/include/linux/pci.h
>> index 9cd2721..7a48b40 100644
>> --- a/include/linux/pci.h
>> +++ b/include/linux/pci.h
>> @@ -1433,6 +1433,15 @@ static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
>>  
>>  #include <asm/pci.h>
>>  
>> +/* Just avoid compile error, will be clean up later */
>> +#ifdef CONFIG_PCI_MSI
>> +
>> +#ifndef pci_msi_chip
>> +#define pci_msi_chip(bus)	NULL
>> +#endif
>> +#endif
> 
> I don't like the mixture of ARM changes and PCI core changes in the same
> patch.  Can you split this into a core patch that does something like this:
> 
>   struct msi_chip * __weak pcibios_msi_controller(struct pci_bus *bus)
>   {
>     return NULL;
>   }
> 
>   struct msi_chip *pci_msi_controller(struct pci_bus *bus)
>   {
>     msi_chip *controller = bus->msi;
> 
>     if (controller)
>       return controller;
>     return pcibios_msi_controller(bus);
>   }
> 
> followed by an ARM patch that puts the msi_chip pointer in struct hw_pci
> and implements pcibios_msi_controller()?

OK, I will split it in half.

> 
> I know you're trying to *remove* weak functions, and this adds one, but
> this section of the series is more about getting rid of the ARM
> pcibios_add_bus() because all it was used for was setting the bus->msi
> pointer.

Yes, agree.

> 
> Eventually we might have a way to stash an MSI controller pointer in the
> generic pci_host_bridge struct, and then the pcibios_msi_controller()
> interface could go away.

Yep, I am doing the work to make a generic pci_host_bridge, and try to rip it out from
pci_create_root_bus, that's also a large changes across many archs.

> 
>> +
>>  /* these helpers provide future and backwards compatibility
>>   * for accessing popular PCI BAR info */
>>  #define pci_resource_start(dev, bar)	((dev)->resource[(bar)].start)
>> -- 
>> 1.7.1
>>
> 
> .
>
diff mbox

Patch

diff --git a/arch/arm/include/asm/mach/pci.h b/arch/arm/include/asm/mach/pci.h
index 7fc4278..59b0d87 100644
--- a/arch/arm/include/asm/mach/pci.h
+++ b/arch/arm/include/asm/mach/pci.h
@@ -22,6 +22,9 @@  struct hw_pci {
 #ifdef CONFIG_PCI_DOMAINS
 	int		domain;
 #endif
+#ifdef CONFIG_PCI_MSI
+	struct msi_chip *msi_chip;
+#endif
 	struct pci_ops	*ops;
 	int		nr_controllers;
 	void		**private_data;
@@ -47,6 +50,9 @@  struct pci_sys_data {
 #ifdef CONFIG_PCI_DOMAINS
 	int		domain;
 #endif
+#ifdef CONFIG_PCI_MSI
+	struct msi_chip *msi_chip;
+#endif
 	struct list_head node;
 	int		busnr;		/* primary bus number			*/
 	u64		mem_offset;	/* bus->cpu memory mapping offset	*/
diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h
index 7e95d85..b562c09 100644
--- a/arch/arm/include/asm/pci.h
+++ b/arch/arm/include/asm/pci.h
@@ -31,6 +31,15 @@  static inline int pci_proc_domain(struct pci_bus *bus)
 }
 #endif /* CONFIG_PCI_DOMAINS */
 
+#ifdef CONFIG_PCI_MSI
+static inline struct msi_chip *pci_msi_chip(struct pci_bus *bus)
+{
+	struct pci_sys_data *root = bus->sysdata;
+
+	return root->msi_chip;
+}
+#endif
+
 /*
  * The PCI address space does equal the physical memory address space.
  * The networking and block device layers use this boolean for bounce
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 17a26c1..a19038d 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -471,6 +471,9 @@  static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
 #ifdef CONFIG_PCI_DOMAINS
 		sys->domain  = hw->domain;
 #endif
+#ifdef CONFIG_PCI_MSI
+		sys->msi_chip = hw->msi_chip;
+#endif
 		sys->busnr   = busnr;
 		sys->swizzle = hw->swizzle;
 		sys->map_irq = hw->map_irq;
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 22e413c..f11108c 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -35,6 +35,9 @@  int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
 	struct msi_chip *chip = dev->bus->msi;
 	int err;
 
+	if (!chip)
+		chip = pci_msi_chip(dev->bus);
+
 	if (!chip || !chip->setup_irq)
 		return -EINVAL;
 
@@ -50,6 +53,9 @@  void __weak arch_teardown_msi_irq(unsigned int irq)
 	struct msi_desc *entry = irq_get_msi_desc(irq);
 	struct msi_chip *chip = entry->dev->bus->msi;
 
+	if (!chip)
+		chip = pci_msi_chip(entry->dev->bus);
+
 	if (!chip || !chip->teardown_irq)
 		return;
 
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 9cd2721..7a48b40 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1433,6 +1433,15 @@  static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
 
 #include <asm/pci.h>
 
+/* Just avoid compile error, will be clean up later */
+#ifdef CONFIG_PCI_MSI
+
+#ifndef pci_msi_chip
+#define pci_msi_chip(bus)	NULL
+#endif
+
+#endif
+
 /* these helpers provide future and backwards compatibility
  * for accessing popular PCI BAR info */
 #define pci_resource_start(dev, bar)	((dev)->resource[(bar)].start)