diff mbox series

[v2,1/1] PCI: loongson: skip scanning unavailable child device

Message ID 20221104072730.14631-1-liupeibao@loongson.cn (mailing list archive)
State Superseded
Headers show
Series [v2,1/1] PCI: loongson: skip scanning unavailable child device | expand

Commit Message

Liu Peibao Nov. 4, 2022, 7:27 a.m. UTC
The PCI Controller of 2k1000 could not mask devices by
setting vender id or device id in configuration space header
as invalid values. When there are pins shareble between
the platform device and PCI device, if the platform device
is preferred, we should not scan this PCI device. In the
above scene, add `status = "disabled"` property in DT node
of this PCI device.

Signed-off-by: Liu Peibao <liupeibao@loongson.cn>
---
V1 -> V2: use existing property "status" instead of adding new property.

 drivers/pci/controller/pci-loongson.c | 57 +++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

Comments

Christophe JAILLET Nov. 4, 2022, 8:43 a.m. UTC | #1
Le 04/11/2022 à 08:27, Liu Peibao a écrit :
> The PCI Controller of 2k1000 could not mask devices by
> setting vender id or device id in configuration space header
> as invalid values. When there are pins shareble between
> the platform device and PCI device, if the platform device
> is preferred, we should not scan this PCI device. In the
> above scene, add `status = "disabled"` property in DT node
> of this PCI device.
> 
> Signed-off-by: Liu Peibao <liupeibao@loongson.cn>
> ---
> V1 -> V2: use existing property "status" instead of adding new property.
> 
>   drivers/pci/controller/pci-loongson.c | 57 +++++++++++++++++++++++++++
>   1 file changed, 57 insertions(+)
> 
> diff --git a/drivers/pci/controller/pci-loongson.c b/drivers/pci/controller/pci-loongson.c
> index 05c50408f13b..cde8a8691867 100644
> --- a/drivers/pci/controller/pci-loongson.c
> +++ b/drivers/pci/controller/pci-loongson.c
> @@ -40,11 +40,21 @@ struct loongson_pci_data {
>   	struct pci_ops *ops;
>   };
>   
> +#ifdef CONFIG_OF
> +struct mask_entry {
> +	struct list_head entry;
> +	unsigned int devfn;
> +};
> +#endif
> +
>   struct loongson_pci {
>   	void __iomem *cfg0_base;
>   	void __iomem *cfg1_base;
>   	struct platform_device *pdev;
>   	const struct loongson_pci_data *data;
> +#ifdef CONFIG_OF
> +	struct list_head masklist;
> +#endif
>   };
>   
>   /* Fixup wrong class code in PCIe bridges */
> @@ -194,6 +204,20 @@ static void __iomem *pci_loongson_map_bus(struct pci_bus *bus,
>   			return NULL;
>   	}
>   
> +#ifdef CONFIG_OF
> +	/* Don't access devices in masklist */
> +	if (pci_is_root_bus(bus)) {
> +		struct list_head *list;
> +		struct mask_entry *entry;
> +
> +		list_for_each(list, &priv->masklist) {
> +			entry = list_entry(list, struct mask_entry, entry);

Hi,

list_for_each_entry() is slighly less verbose.

> +			if (devfn == entry->devfn)
> +				return NULL;
> +		}
> +	}
> +#endif
> +
>   	/* CFG0 can only access standard space */
>   	if (where < PCI_CFG_SPACE_SIZE && priv->cfg0_base)
>   		return cfg0_map(priv, bus, devfn, where);
> @@ -206,6 +230,36 @@ static void __iomem *pci_loongson_map_bus(struct pci_bus *bus,
>   }
>   
>   #ifdef CONFIG_OF
> +static int setup_masklist(struct loongson_pci *priv)
> +{
> +	struct device *dev = &priv->pdev->dev;
> +	struct device_node *dn, *parent = dev->of_node;
> +	struct mask_entry *entry;
> +	int devfn;
> +
> +	INIT_LIST_HEAD(&priv->masklist);
> +
> +	for_each_child_of_node(parent, dn) {
> +		/*
> +		 * if device is not available, add this to masklist
> +		 * to avoid scanning it.
> +		 */
> +		if (!of_device_is_available(dn)) {
> +			devfn = of_pci_get_devfn(dn);
> +			if (devfn < 0)
> +				continue;
> +
> +			entry = devm_kzalloc(dev, sizeof(entry), GFP_KERNEL);

sizeof(*entry)?

> +			if (!entry)
> +				return -ENOMEM;
> +
> +			entry->devfn = devfn;
> +			list_add_tail(&entry->entry, &priv->masklist);
> +		}
> +	}
> +
> +	return 0;
> +}
>   
>   static int loongson_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
>   {
> @@ -305,6 +359,9 @@ static int loongson_pci_probe(struct platform_device *pdev)
>   		}
>   	}
>   
> +	if (setup_masklist(priv))
> +		return -ENOMEM;
> +
>   	bridge->sysdata = priv;
>   	bridge->ops = priv->data->ops;
>   	bridge->map_irq = loongson_map_irq;
Liu Peibao Nov. 4, 2022, 10:43 a.m. UTC | #2
On 11/4/22 4:43 PM, Christophe JAILLET wrote:
> Le 04/11/2022 à 08:27, Liu Peibao a écrit :
>>   +#ifdef CONFIG_OF
>> +    /* Don't access devices in masklist */
>> +    if (pci_is_root_bus(bus)) {
>> +        struct list_head *list;
>> +        struct mask_entry *entry;
>> +
>> +        list_for_each(list, &priv->masklist) {
>> +            entry = list_entry(list, struct mask_entry, entry);
> 
> Hi,
> 
> list_for_each_entry() is slighly less verbose.
> 

OK, I will update the patch with list_for_each_entry().

>> +            if (devfn == entry->devfn)
>> +                return NULL;
>> +        }
>> +    }
>> +#endif
>> +
>>       /* CFG0 can only access standard space */
>>       if (where < PCI_CFG_SPACE_SIZE && priv->cfg0_base)
>>           return cfg0_map(priv, bus, devfn, where);
>> @@ -206,6 +230,36 @@ static void __iomem *pci_loongson_map_bus(struct pci_bus *bus,
>>   }
>>     #ifdef CONFIG_OF
>> +static int setup_masklist(struct loongson_pci *priv)
>> +{
>> +    struct device *dev = &priv->pdev->dev;
>> +    struct device_node *dn, *parent = dev->of_node;
>> +    struct mask_entry *entry;
>> +    int devfn;
>> +
>> +    INIT_LIST_HEAD(&priv->masklist);
>> +
>> +    for_each_child_of_node(parent, dn) {
>> +        /*
>> +         * if device is not available, add this to masklist
>> +         * to avoid scanning it.
>> +         */
>> +        if (!of_device_is_available(dn)) {
>> +            devfn = of_pci_get_devfn(dn);
>> +            if (devfn < 0)
>> +                continue;
>> +
>> +            entry = devm_kzalloc(dev, sizeof(entry), GFP_KERNEL);
> 
> sizeof(*entry)?
>

That really is a bug, thanks!

BR,
Peibao
 
>> +            if (!entry)
>> +                return -ENOMEM;
>> +
diff mbox series

Patch

diff --git a/drivers/pci/controller/pci-loongson.c b/drivers/pci/controller/pci-loongson.c
index 05c50408f13b..cde8a8691867 100644
--- a/drivers/pci/controller/pci-loongson.c
+++ b/drivers/pci/controller/pci-loongson.c
@@ -40,11 +40,21 @@  struct loongson_pci_data {
 	struct pci_ops *ops;
 };
 
+#ifdef CONFIG_OF
+struct mask_entry {
+	struct list_head entry;
+	unsigned int devfn;
+};
+#endif
+
 struct loongson_pci {
 	void __iomem *cfg0_base;
 	void __iomem *cfg1_base;
 	struct platform_device *pdev;
 	const struct loongson_pci_data *data;
+#ifdef CONFIG_OF
+	struct list_head masklist;
+#endif
 };
 
 /* Fixup wrong class code in PCIe bridges */
@@ -194,6 +204,20 @@  static void __iomem *pci_loongson_map_bus(struct pci_bus *bus,
 			return NULL;
 	}
 
+#ifdef CONFIG_OF
+	/* Don't access devices in masklist */
+	if (pci_is_root_bus(bus)) {
+		struct list_head *list;
+		struct mask_entry *entry;
+
+		list_for_each(list, &priv->masklist) {
+			entry = list_entry(list, struct mask_entry, entry);
+			if (devfn == entry->devfn)
+				return NULL;
+		}
+	}
+#endif
+
 	/* CFG0 can only access standard space */
 	if (where < PCI_CFG_SPACE_SIZE && priv->cfg0_base)
 		return cfg0_map(priv, bus, devfn, where);
@@ -206,6 +230,36 @@  static void __iomem *pci_loongson_map_bus(struct pci_bus *bus,
 }
 
 #ifdef CONFIG_OF
+static int setup_masklist(struct loongson_pci *priv)
+{
+	struct device *dev = &priv->pdev->dev;
+	struct device_node *dn, *parent = dev->of_node;
+	struct mask_entry *entry;
+	int devfn;
+
+	INIT_LIST_HEAD(&priv->masklist);
+
+	for_each_child_of_node(parent, dn) {
+		/*
+		 * if device is not available, add this to masklist
+		 * to avoid scanning it.
+		 */
+		if (!of_device_is_available(dn)) {
+			devfn = of_pci_get_devfn(dn);
+			if (devfn < 0)
+				continue;
+
+			entry = devm_kzalloc(dev, sizeof(entry), GFP_KERNEL);
+			if (!entry)
+				return -ENOMEM;
+
+			entry->devfn = devfn;
+			list_add_tail(&entry->entry, &priv->masklist);
+		}
+	}
+
+	return 0;
+}
 
 static int loongson_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
@@ -305,6 +359,9 @@  static int loongson_pci_probe(struct platform_device *pdev)
 		}
 	}
 
+	if (setup_masklist(priv))
+		return -ENOMEM;
+
 	bridge->sysdata = priv;
 	bridge->ops = priv->data->ops;
 	bridge->map_irq = loongson_map_irq;