lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <af9b6bb3-a98d-4fb6-b51e-b48bca61dada@amd.com>
Date:   Mon, 26 Jun 2023 10:34:05 -0700
From:   Lizhi Hou <lizhi.hou@....com>
To:     Bjorn Helgaas <helgaas@...nel.org>
CC:     <linux-pci@...r.kernel.org>, <devicetree@...r.kernel.org>,
        <linux-kernel@...r.kernel.org>, <robh@...nel.org>,
        <max.zhen@....com>, <sonal.santan@....com>,
        <stefano.stabellini@...inx.com>
Subject: Re: [PATCH V9 2/5] PCI: Create device tree node for selected devices


On 6/21/23 13:22, Bjorn Helgaas wrote:
> In subject, IIUC this patch does not actually create device tree nodes
> for selected devices.  It looks like it:
>
>    - Adds an of_pci_make_dev_node() *interface* that can be used to
>      create this node
>
>    - Creates such a node for *every* bridge
>
>    - Does nothing at all for "selected devices" or the Xilinx Alveo
>
> On Wed, Jun 21, 2023 at 10:34:06AM -0700, Lizhi Hou wrote:
>> The PCI endpoint device such as Xilinx Alveo PCI card maps the register
>> spaces from multiple hardware peripherals to its PCI BAR. Normally,
>> the PCI core discovers devices and BARs using the PCI enumeration process.
>> There is no infrastructure to discover the hardware peripherals that are
>> present in a PCI device, and which can be accessed through the PCI BARs.
>>
>> For Alveo PCI card, the card firmware provides a flattened device tree to
>> describe the hardware peripherals on its BARs. The Alveo card driver can
>> load this flattened device tree and leverage device tree framework to
>> generate platform devices for the hardware peripherals eventually.
> The Alveo details are relevant to the quirk patch but not to *this*
> patch.
>
> But the reason for creating a node for every bridge device *is*
> relevant and should be included here, since that change affects
> everybody that uses OF.
>
>> Apparently, the device tree framework requires a device tree node for the
>> PCI device. Thus, it can generate the device tree nodes for hardware
>> peripherals underneath. Because PCI is self discoverable bus, there might
>> not be a device tree node created for PCI devices. This patch is to add
>> support to generate device tree node for PCI devices.
> s/This patch is to add/Add/
>
>> Added a kernel option. When the option is turned on, the kernel will
>> generate device tree nodes for PCI bridges unconditionally.
> s/Added a kernel option/Add a PCI_DYNAMIC_OF_NODES config option/
> (Be specific, and way what the patch does, not what you did.)
>
>> Initially, the basic properties are added for the dynamically generated
>> device tree nodes.
> Make this specific, e.g., list the specific properties added.

I rewrote the description as below. Does it look better?

     PCI: Create device tree node for bridge

     The PCI endpoint device such as Xilinx Alveo PCI card maps the register
     spaces from multiple hardware peripherals to its PCI BAR. Normally,
     the PCI core discovers devices and BARs using the PCI enumeration 
process.
     There is no infrastructure to discover the hardware peripherals 
that are
     present in a PCI device, and which can be accessed through the PCI 
BARs.

     Apparently, the device tree framework requires a device tree node 
for the
     PCI device. Thus, it can generate the device tree nodes for hardware
     peripherals underneath. Because PCI is self discoverable bus, there 
might
     not be a device tree node created for PCI devices. Furthermore, if 
the PCI
     device is hot pluggable, when it is plugged in, the device tree 
nodes for
     its parent bridges are required. Add support to generate device 
tree node
     for PCI bridges.

     Added an of_pci_make_dev_node() interface that can be used to create
     device tree node for PCI devices.

     Added a PCI_DYNAMIC_OF_NODES config option. When the option is 
turned on,
     the kernel will generate device tree nodes for PCI bridges 
unconditionally.

     Initially, the basic properties are added for the dynamically generated
     device tree nodes which include #address-cells, #size-cells, 
device_type,
     compatible, ranges, reg.

>
>> +config PCI_DYNAMIC_OF_NODES
>> +	bool "Create Devicetree nodes for PCI devices"
>> +	depends on OF
>> +	select OF_DYNAMIC
>> +	help
>> +	  This option enables support for generating device tree nodes for some
>> +	  PCI devices. Thus, the driver of this kind can load and overlay
>> +	  flattened device tree for its downstream devices.
>> +
>> +	  Once this option is selected, the device tree nodes will be generated
>> +	  for all PCI bridges.
> Is there a convention for using "devicetree" vs "device tree"?  The
> help message uses both and it would be nice to only use one or the
> other.
Ok. Will use "device tree".
>
>> @@ -501,8 +501,10 @@ static int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *
>>   		 * to rely on this function (you ship a firmware that doesn't
>>   		 * create device nodes for all PCI devices).
>>   		 */
>> -		if (ppnode)
>> +		if (ppnode && of_property_present(ppnode, "interrupt-map"))
> Maybe this deserves a comment?  The connection between "interrupt-map"
> and the rest of this patch isn't obvious to me.
>
> Also, it looks like this happens for *everybody*, regardless of
> PCI_DYNAMIC_OF_NODES, which seems a little suspect.  If it's an
> unrelated bug fix it should be a different patch.

This is not a bug fix. The check will distinguish between device tree 
nodes automatically created for pci bridges by this patch with those 
created by a DT based system. With this patch, device tree nodes are 
created for pci bridges, thus ppnode here will be non-zero and we will 
break out of the loop. In order to still use 
pci_swizzle_interrupt_pin(), checking “interrupt-map” for ppnode is 
added here.


After thinking about this more, using “interrupt-map” property may not 
be correct for the cases where ppnode is not dynamically generated and 
it does not have “interrupt-map”. So, I would introduce a new property 
“dynamic” for pci bridge nodes generated dynamically. And change the 
code to: if (ppnode && of_property_present(ppnode, "dynamic")).


Does this make sense?
>
>>   			break;
>> +		else
>> +			ppnode = NULL;
>> +void of_pci_make_dev_node(struct pci_dev *pdev)
>> +{
>> +	struct device_node *ppnode, *np = NULL;
>> +	const char *pci_type = "dev";
>> +	struct of_changeset *cset;
>> +	const char *name;
>> +	int ret;
>> +
>> +	/*
>> +	 * If there is already a device tree node linked to this device,
>> +	 * return immediately.
>> +	 */
>> +	if (pci_device_to_OF_node(pdev))
>> +		return;
>> +
>> +	/* Check if there is device tree node for parent device */
>> +	if (!pdev->bus->self)
>> +		ppnode = pdev->bus->dev.of_node;
>> +	else
>> +		ppnode = pdev->bus->self->dev.of_node;
>> +	if (!ppnode)
>> +		return;
>> +
>> +	if (pci_is_bridge(pdev))
>> +		pci_type = "pci";
> Initialize pci_type = "dev" here instead of way up top:
>
>    if (pci_is_bridge(pdev))
>      pci_type = "pci";
>    else
>      pci_type = "dev";
sure.
>
>> +	name = kasprintf(GFP_KERNEL, "%s@%x,%x", pci_type,
>> +			 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
>> +static int of_pci_prop_ranges(struct pci_dev *pdev, struct of_changeset *ocs,
>> +			      struct device_node *np)
>> +{
>> +	struct of_pci_range *rp;
>> +	struct resource *res;
>> +	int i = 0, j, ret;
>> +	u32 flags, num;
>> +	u64 val64;
>> +
>> +	if (pci_is_bridge(pdev)) {
>> +		num = PCI_BRIDGE_RESOURCE_NUM;
>> +		res = &pdev->resource[PCI_BRIDGE_RESOURCES];
>> +	} else {
>> +		num = PCI_STD_NUM_BARS;
>> +		res = &pdev->resource[PCI_STD_RESOURCES];
>> +	}
>> +
>> +	rp = kcalloc(num, sizeof(*rp), GFP_KERNEL);
>> +	if (!rp)
>> +		return -ENOMEM;
>> +
>> +	for (j = 0; j < num; j++) {
> Initialize i = 0 here so it's connected with the use:
>
>    for (i = 0, j = 0; j < num; ...)
ok.
>
>> +		if (!resource_size(&res[j]))
>> +			continue;
>> +
>> +		if (of_pci_get_addr_flags(&res[j], &flags))
>> +			continue;
>> +
>> +		val64 = res[j].start;
>> +		of_pci_set_address(pdev, rp[i].parent_addr, val64, 0, flags,
>> +				   false);
>> +		if (pci_is_bridge(pdev)) {
>> +			memcpy(rp[i].child_addr, rp[i].parent_addr,
>> +			       sizeof(rp[i].child_addr));
>> +		} else {
>> +			/*
>> +			 * For endpoint device, the lower 64-bits of child
>> +			 * address is always zero.
> For the non-OF folks (like me), can you say what the semantics of
> parent_addr vs child_addr are?  I suppose maybe parent_addr is an
> address on the primary side of a bridge and child_addr is the
> corresponding address on the secondary side?
>
> And PCI bridges don't perform address translation, so they are
> identical?
I will add more comments here.
>
>> +			 */
>> +			rp[i].child_addr[0] = j;
>> +		}
>> +int of_pci_add_properties(struct pci_dev *pdev, struct of_changeset *ocs,
>> +			  struct device_node *np)
>> +{
>> +	int ret = 0;
>> +
>> +	if (pci_is_bridge(pdev)) {
>> +		ret |= of_changeset_add_prop_string(ocs, np, "device_type",
>> +						    "pci");
>> +	}
>> +
>> +	ret |= of_pci_prop_ranges(pdev, ocs, np);
>> +	ret |= of_changeset_add_prop_u32(ocs, np, "#address-cells",
>> +					 OF_PCI_ADDRESS_CELLS);
>> +	ret |= of_changeset_add_prop_u32(ocs, np, "#size-cells",
>> +					 OF_PCI_SIZE_CELLS);
>> +	ret |= of_pci_prop_reg(pdev, ocs, np);
>> +	ret |= of_pci_prop_compatible(pdev, ocs, np);
>> +
>> +	/*
>> +	 * The added properties will be released when the
>> +	 * changeset is destroyed.
>> +	 */
> I don't think it's meaningful to OR together the "negative error
> values" returned by all these functions.  Presumably those are things
> like -EINVAL, -ENOMEM, etc.  ORing them together is admittedly
> non-zero, but yields nonsense.
ok. I will return for each failure.
>
>> +	return ret;
>> +static inline void
>> +of_pci_make_dev_node(struct pci_dev *pdev)
>> +{
>> +}
>> +
>> +static inline void
>> +of_pci_remove_node(struct pci_dev *pdev)
>> +{
>> +}
> Pull these functions all onto one line, like other similar stubs in
> this file.
Sure.
>
>> +#endif /* CONFIG_PCI_DYNAMIC_OF_NODES */
> Unnecessary comment since this is all 10 lines.

Will remove it.

Thanks,

Lizhi

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ