diff mbox

[PATCHv4,05/11] of: pci: add registry of MSI chips

Message ID 1372686136-1370-6-git-send-email-thomas.petazzoni@free-electrons.com (mailing list archive)
State New, archived
Delegated to: Bjorn Helgaas
Headers show

Commit Message

Thomas Petazzoni July 1, 2013, 1:42 p.m. UTC
This commit adds a very basic registry of msi_chip structures, so that
an IRQ controller driver can register an msi_chip, and a PCIe host
controller can find it, based on a 'struct device_node'.

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
 drivers/of/of_pci.c    | 40 ++++++++++++++++++++++++++++++++++++++++
 include/linux/msi.h    |  2 ++
 include/linux/of_pci.h | 12 ++++++++++++
 3 files changed, 54 insertions(+)

Comments

Bjorn Helgaas July 5, 2013, 9:56 p.m. UTC | #1
On Mon, Jul 1, 2013 at 7:42 AM, Thomas Petazzoni
<thomas.petazzoni@free-electrons.com> wrote:
> This commit adds a very basic registry of msi_chip structures, so that
> an IRQ controller driver can register an msi_chip, and a PCIe host
> controller can find it, based on a 'struct device_node'.
>
> Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> ---
>  drivers/of/of_pci.c    | 40 ++++++++++++++++++++++++++++++++++++++++
>  include/linux/msi.h    |  2 ++
>  include/linux/of_pci.h | 12 ++++++++++++
>  3 files changed, 54 insertions(+)
>
> diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
> index 42c687a..f516632 100644
> --- a/drivers/of/of_pci.c
> +++ b/drivers/of/of_pci.c
> @@ -89,3 +89,43 @@ int of_pci_parse_bus_range(struct device_node *node, struct resource *res)
>         return 0;
>  }
>  EXPORT_SYMBOL_GPL(of_pci_parse_bus_range);
> +
> +#ifdef CONFIG_PCI_MSI
> +
> +static LIST_HEAD(msi_chip_list);
> +static DEFINE_MUTEX(msi_chip_mutex);
> +
> +int of_msi_chip_add(struct msi_chip *chip)
> +{
> +       if (! of_property_read_bool(chip->of_node, "msi-controller"))

The space between "! of_property..." is atypical.

> +               return -EINVAL;
> +
> +       mutex_lock(&msi_chip_mutex);
> +       list_add(&chip->list, &msi_chip_list);
> +       mutex_unlock(&msi_chip_mutex);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_msi_chip_add);
> +
> +void of_msi_chip_remove(struct msi_chip *chip)
> +{
> +       mutex_lock(&msi_chip_mutex);
> +       list_del(&chip->list);
> +       mutex_unlock(&msi_chip_mutex);
> +}
> +EXPORT_SYMBOL_GPL(of_msi_chip_remove);
> +
> +struct msi_chip *of_find_msi_chip_by_node(struct device_node *of_node)
> +{
> +       struct msi_chip *c;

Normally there's a blank line here.

The list traversal below isn't safe, is it?  A simultaneous remove,
e.g., of an MSI chip unrelated to the one we're looking up, might
change the list while we're traversing it.

> +       list_for_each_entry(c, &msi_chip_list, list) {
> +               if (c->of_node == of_node)
> +                       return c;
> +       }
> +
> +       return NULL;
> +}
> +EXPORT_SYMBOL_GPL(of_find_msi_chip_by_node);
> +
> +#endif /* CONFIG_PCI_MSI */
> diff --git a/include/linux/msi.h b/include/linux/msi.h
> index 5b357d92..9e1a44b 100644
> --- a/include/linux/msi.h
> +++ b/include/linux/msi.h
> @@ -66,6 +66,8 @@ void default_teardown_msi_irqs(struct pci_dev *dev);
>  struct msi_chip {
>         struct module *owner;
>         struct device *dev;
> +       struct device_node *of_node;
> +       struct list_head list;
>
>         int (*setup_irq)(struct msi_chip *chip, struct pci_dev *dev,
>                          struct msi_desc *desc);
> diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
> index 7a04826..99e4361 100644
> --- a/include/linux/of_pci.h
> +++ b/include/linux/of_pci.h
> @@ -2,6 +2,7 @@
>  #define __OF_PCI_H
>
>  #include <linux/pci.h>
> +#include <linux/msi.h>
>
>  struct pci_dev;
>  struct of_irq;
> @@ -13,4 +14,15 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
>  int of_pci_get_devfn(struct device_node *np);
>  int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
>
> +#if defined(CONFIG_OF) && defined(CONFIG_PCI_MSI)
> +int of_msi_chip_add(struct msi_chip *chip);
> +void of_msi_chip_remove(struct msi_chip *chip);
> +struct msi_chip *of_find_msi_chip_by_node(struct device_node *of_node);
> +#else
> +static inline int of_msi_chip_add(struct msi_chip *chip) { return -EINVAL; }
> +static inline void of_msi_chip_remove(struct msi_chip *chip) { }
> +static inline struct msi_chip *
> +of_find_msi_chip_by_node(struct device_node *of_node) { return NULL };
> +#endif
> +
>  #endif
> --
> 1.8.1.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
Thomas Petazzoni July 5, 2013, 10:06 p.m. UTC | #2
Dear Bjorn Helgaas,

On Fri, 5 Jul 2013 15:56:55 -0600, Bjorn Helgaas wrote:

> > +int of_msi_chip_add(struct msi_chip *chip)
> > +{
> > +       if (! of_property_read_bool(chip->of_node, "msi-controller"))
> 
> The space between "! of_property..." is atypical.

Indeed.


> > +struct msi_chip *of_find_msi_chip_by_node(struct device_node *of_node)
> > +{
> > +       struct msi_chip *c;
> 
> Normally there's a blank line here.
> 
> The list traversal below isn't safe, is it?  A simultaneous remove,
> e.g., of an MSI chip unrelated to the one we're looking up, might
> change the list while we're traversing it.

True, will fix!

Thomas
Thomas Petazzoni July 8, 2013, 11:23 a.m. UTC | #3
Grant, Rob,

Would it be possible to get your feeling about the below patch? Are you
ok with the idea of this msi_chip registry, based on device_node
pointer? This is the last piece of this patch set that needs an
approval in terms of general approach.

I am at Linaro Connect this week, so if you want to discuss this live,
do not hesitate to ping me.

Thanks a lot,

Thomas

On Mon,  1 Jul 2013 15:42:10 +0200, Thomas Petazzoni wrote:
> This commit adds a very basic registry of msi_chip structures, so that
> an IRQ controller driver can register an msi_chip, and a PCIe host
> controller can find it, based on a 'struct device_node'.
> 
> Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> ---
>  drivers/of/of_pci.c    | 40 ++++++++++++++++++++++++++++++++++++++++
>  include/linux/msi.h    |  2 ++
>  include/linux/of_pci.h | 12 ++++++++++++
>  3 files changed, 54 insertions(+)
> 
> diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
> index 42c687a..f516632 100644
> --- a/drivers/of/of_pci.c
> +++ b/drivers/of/of_pci.c
> @@ -89,3 +89,43 @@ int of_pci_parse_bus_range(struct device_node *node, struct resource *res)
>  	return 0;
>  }
>  EXPORT_SYMBOL_GPL(of_pci_parse_bus_range);
> +
> +#ifdef CONFIG_PCI_MSI
> +
> +static LIST_HEAD(msi_chip_list);
> +static DEFINE_MUTEX(msi_chip_mutex);
> +
> +int of_msi_chip_add(struct msi_chip *chip)
> +{
> +	if (! of_property_read_bool(chip->of_node, "msi-controller"))
> +		return -EINVAL;
> +
> +	mutex_lock(&msi_chip_mutex);
> +	list_add(&chip->list, &msi_chip_list);
> +	mutex_unlock(&msi_chip_mutex);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_msi_chip_add);
> +
> +void of_msi_chip_remove(struct msi_chip *chip)
> +{
> +	mutex_lock(&msi_chip_mutex);
> +	list_del(&chip->list);
> +	mutex_unlock(&msi_chip_mutex);
> +}
> +EXPORT_SYMBOL_GPL(of_msi_chip_remove);
> +
> +struct msi_chip *of_find_msi_chip_by_node(struct device_node *of_node)
> +{
> +	struct msi_chip *c;
> +	list_for_each_entry(c, &msi_chip_list, list) {
> +		if (c->of_node == of_node)
> +			return c;
> +	}
> +
> +	return NULL;
> +}
> +EXPORT_SYMBOL_GPL(of_find_msi_chip_by_node);
> +
> +#endif /* CONFIG_PCI_MSI */
> diff --git a/include/linux/msi.h b/include/linux/msi.h
> index 5b357d92..9e1a44b 100644
> --- a/include/linux/msi.h
> +++ b/include/linux/msi.h
> @@ -66,6 +66,8 @@ void default_teardown_msi_irqs(struct pci_dev *dev);
>  struct msi_chip {
>  	struct module *owner;
>  	struct device *dev;
> +	struct device_node *of_node;
> +	struct list_head list;
>  
>  	int (*setup_irq)(struct msi_chip *chip, struct pci_dev *dev,
>  			 struct msi_desc *desc);
> diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
> index 7a04826..99e4361 100644
> --- a/include/linux/of_pci.h
> +++ b/include/linux/of_pci.h
> @@ -2,6 +2,7 @@
>  #define __OF_PCI_H
>  
>  #include <linux/pci.h>
> +#include <linux/msi.h>
>  
>  struct pci_dev;
>  struct of_irq;
> @@ -13,4 +14,15 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
>  int of_pci_get_devfn(struct device_node *np);
>  int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
>  
> +#if defined(CONFIG_OF) && defined(CONFIG_PCI_MSI)
> +int of_msi_chip_add(struct msi_chip *chip);
> +void of_msi_chip_remove(struct msi_chip *chip);
> +struct msi_chip *of_find_msi_chip_by_node(struct device_node *of_node);
> +#else
> +static inline int of_msi_chip_add(struct msi_chip *chip) { return -EINVAL; }
> +static inline void of_msi_chip_remove(struct msi_chip *chip) { }
> +static inline struct msi_chip *
> +of_find_msi_chip_by_node(struct device_node *of_node) { return NULL };
> +#endif
> +
>  #endif
Rob Herring July 9, 2013, 1:43 p.m. UTC | #4
On Mon, Jul 1, 2013 at 8:42 AM, Thomas Petazzoni
<thomas.petazzoni@free-electrons.com> wrote:
> This commit adds a very basic registry of msi_chip structures, so that
> an IRQ controller driver can register an msi_chip, and a PCIe host
> controller can find it, based on a 'struct device_node'.
>
> Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> ---
>  drivers/of/of_pci.c    | 40 ++++++++++++++++++++++++++++++++++++++++
>  include/linux/msi.h    |  2 ++
>  include/linux/of_pci.h | 12 ++++++++++++
>  3 files changed, 54 insertions(+)
>
> diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
> index 42c687a..f516632 100644
> --- a/drivers/of/of_pci.c
> +++ b/drivers/of/of_pci.c
> @@ -89,3 +89,43 @@ int of_pci_parse_bus_range(struct device_node *node, struct resource *res)
>         return 0;
>  }
>  EXPORT_SYMBOL_GPL(of_pci_parse_bus_range);
> +
> +#ifdef CONFIG_PCI_MSI
> +
> +static LIST_HEAD(msi_chip_list);
> +static DEFINE_MUTEX(msi_chip_mutex);
> +
> +int of_msi_chip_add(struct msi_chip *chip)

Perhaps of_pci_msi_chip_add instead.

> +{
> +       if (! of_property_read_bool(chip->of_node, "msi-controller"))
> +               return -EINVAL;
> +
> +       mutex_lock(&msi_chip_mutex);
> +       list_add(&chip->list, &msi_chip_list);
> +       mutex_unlock(&msi_chip_mutex);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_msi_chip_add);
> +
> +void of_msi_chip_remove(struct msi_chip *chip)

ditto

> +{
> +       mutex_lock(&msi_chip_mutex);
> +       list_del(&chip->list);
> +       mutex_unlock(&msi_chip_mutex);
> +}
> +EXPORT_SYMBOL_GPL(of_msi_chip_remove);
> +
> +struct msi_chip *of_find_msi_chip_by_node(struct device_node *of_node)

ditto.

> +{
> +       struct msi_chip *c;
> +       list_for_each_entry(c, &msi_chip_list, list) {

Need the safe variant here?

Rob

> +               if (c->of_node == of_node)
> +                       return c;
> +       }
> +
> +       return NULL;
> +}
> +EXPORT_SYMBOL_GPL(of_find_msi_chip_by_node);
> +
> +#endif /* CONFIG_PCI_MSI */
> diff --git a/include/linux/msi.h b/include/linux/msi.h
> index 5b357d92..9e1a44b 100644
> --- a/include/linux/msi.h
> +++ b/include/linux/msi.h
> @@ -66,6 +66,8 @@ void default_teardown_msi_irqs(struct pci_dev *dev);
>  struct msi_chip {
>         struct module *owner;
>         struct device *dev;
> +       struct device_node *of_node;
> +       struct list_head list;
>
>         int (*setup_irq)(struct msi_chip *chip, struct pci_dev *dev,
>                          struct msi_desc *desc);
> diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
> index 7a04826..99e4361 100644
> --- a/include/linux/of_pci.h
> +++ b/include/linux/of_pci.h
> @@ -2,6 +2,7 @@
>  #define __OF_PCI_H
>
>  #include <linux/pci.h>
> +#include <linux/msi.h>
>
>  struct pci_dev;
>  struct of_irq;
> @@ -13,4 +14,15 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
>  int of_pci_get_devfn(struct device_node *np);
>  int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
>
> +#if defined(CONFIG_OF) && defined(CONFIG_PCI_MSI)
> +int of_msi_chip_add(struct msi_chip *chip);
> +void of_msi_chip_remove(struct msi_chip *chip);
> +struct msi_chip *of_find_msi_chip_by_node(struct device_node *of_node);
> +#else
> +static inline int of_msi_chip_add(struct msi_chip *chip) { return -EINVAL; }
> +static inline void of_msi_chip_remove(struct msi_chip *chip) { }
> +static inline struct msi_chip *
> +of_find_msi_chip_by_node(struct device_node *of_node) { return NULL };
> +#endif
> +
>  #endif
> --
> 1.8.1.2
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
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
Thomas Petazzoni July 9, 2013, 2:01 p.m. UTC | #5
Rob,

On Tue, 9 Jul 2013 08:43:36 -0500, Rob Herring wrote:

> > +int of_msi_chip_add(struct msi_chip *chip)
> 
> Perhaps of_pci_msi_chip_add instead.

Sure, makes sense.

> > +{
> > +       struct msi_chip *c;
> > +       list_for_each_entry(c, &msi_chip_list, list) {
> 
> Need the safe variant here?

As suggested by Bjorn, I've changed this function to grab the
msi_chip_mutex while traversing the list.

Does your e-mail implies that the general approach seems ok? If so,
I'll resend an updated v5 version taking into account the comments
that I have received on this v4.

Thanks!

Thomas
Bjorn Helgaas July 9, 2013, 4:30 p.m. UTC | #6
On Tue, Jul 9, 2013 at 8:01 AM, Thomas Petazzoni
<thomas.petazzoni@free-electrons.com> wrote:
> On Tue, 9 Jul 2013 08:43:36 -0500, Rob Herring wrote:
>> > +{
>> > +       struct msi_chip *c;
>> > +       list_for_each_entry(c, &msi_chip_list, list) {
>>
>> Need the safe variant here?
>
> As suggested by Bjorn, I've changed this function to grab the
> msi_chip_mutex while traversing the list.

The "safe" list functions don't do any mutual exclusion.  The only
safety they provide is that we won't go in the weeds if the body of
the loop deletes the current list entry.  This loop doesn't delete
entries, so we don't need the safe variant.

Bjorn
--
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
Rob Herring July 9, 2013, 10:52 p.m. UTC | #7
On 07/09/2013 09:01 AM, Thomas Petazzoni wrote:
> Rob,
> 
> On Tue, 9 Jul 2013 08:43:36 -0500, Rob Herring wrote:
> 
>>> +int of_msi_chip_add(struct msi_chip *chip)
>>
>> Perhaps of_pci_msi_chip_add instead.
> 
> Sure, makes sense.
> 
>>> +{
>>> +       struct msi_chip *c;
>>> +       list_for_each_entry(c, &msi_chip_list, list) {
>>
>> Need the safe variant here?
> 
> As suggested by Bjorn, I've changed this function to grab the
> msi_chip_mutex while traversing the list.
> 
> Does your e-mail implies that the general approach seems ok? If so,
> I'll resend an updated v5 version taking into account the comments
> that I have received on this v4.

Yes. Since it is only trivial comments, you can add my ack.

Acked-by: Rob Herring <rob.herring@calxeda.com>

Rob

> 
> Thanks!
> 
> Thomas
> 

--
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
diff mbox

Patch

diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index 42c687a..f516632 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -89,3 +89,43 @@  int of_pci_parse_bus_range(struct device_node *node, struct resource *res)
 	return 0;
 }
 EXPORT_SYMBOL_GPL(of_pci_parse_bus_range);
+
+#ifdef CONFIG_PCI_MSI
+
+static LIST_HEAD(msi_chip_list);
+static DEFINE_MUTEX(msi_chip_mutex);
+
+int of_msi_chip_add(struct msi_chip *chip)
+{
+	if (! of_property_read_bool(chip->of_node, "msi-controller"))
+		return -EINVAL;
+
+	mutex_lock(&msi_chip_mutex);
+	list_add(&chip->list, &msi_chip_list);
+	mutex_unlock(&msi_chip_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(of_msi_chip_add);
+
+void of_msi_chip_remove(struct msi_chip *chip)
+{
+	mutex_lock(&msi_chip_mutex);
+	list_del(&chip->list);
+	mutex_unlock(&msi_chip_mutex);
+}
+EXPORT_SYMBOL_GPL(of_msi_chip_remove);
+
+struct msi_chip *of_find_msi_chip_by_node(struct device_node *of_node)
+{
+	struct msi_chip *c;
+	list_for_each_entry(c, &msi_chip_list, list) {
+		if (c->of_node == of_node)
+			return c;
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(of_find_msi_chip_by_node);
+
+#endif /* CONFIG_PCI_MSI */
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 5b357d92..9e1a44b 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -66,6 +66,8 @@  void default_teardown_msi_irqs(struct pci_dev *dev);
 struct msi_chip {
 	struct module *owner;
 	struct device *dev;
+	struct device_node *of_node;
+	struct list_head list;
 
 	int (*setup_irq)(struct msi_chip *chip, struct pci_dev *dev,
 			 struct msi_desc *desc);
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
index 7a04826..99e4361 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -2,6 +2,7 @@ 
 #define __OF_PCI_H
 
 #include <linux/pci.h>
+#include <linux/msi.h>
 
 struct pci_dev;
 struct of_irq;
@@ -13,4 +14,15 @@  struct device_node *of_pci_find_child_device(struct device_node *parent,
 int of_pci_get_devfn(struct device_node *np);
 int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
 
+#if defined(CONFIG_OF) && defined(CONFIG_PCI_MSI)
+int of_msi_chip_add(struct msi_chip *chip);
+void of_msi_chip_remove(struct msi_chip *chip);
+struct msi_chip *of_find_msi_chip_by_node(struct device_node *of_node);
+#else
+static inline int of_msi_chip_add(struct msi_chip *chip) { return -EINVAL; }
+static inline void of_msi_chip_remove(struct msi_chip *chip) { }
+static inline struct msi_chip *
+of_find_msi_chip_by_node(struct device_node *of_node) { return NULL };
+#endif
+
 #endif