[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <22f8e42c-c766-cd04-c1a9-9f0e15d80f39@amd.com>
Date: Tue, 25 Apr 2023 08:32:45 -0700
From: Lizhi Hou <lizhi.hou@....com>
To: Rob Herring <robh@...nel.org>
CC: <linux-pci@...r.kernel.org>, <devicetree@...r.kernel.org>,
<linux-kernel@...r.kernel.org>, <frowand.list@...il.com>,
<helgaas@...nel.org>, <clement.leger@...tlin.com>,
<max.zhen@....com>, <sonal.santan@....com>, <larry.liu@....com>,
<brian.xu@....com>, <stefano.stabellini@...inx.com>,
<trix@...hat.com>
Subject: Re: [PATCH V8 2/3] PCI: Create device tree node for selected devices
On 4/25/23 08:02, Rob Herring wrote:
> On Thu, Apr 20, 2023 at 11:05 AM Lizhi Hou <lizhi.hou@....com> wrote:
>> On 4/19/23 16:11, Rob Herring wrote:
>>> On Tue, Apr 18, 2023 at 09:19:53PM -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.
> [...]
>
>>>> diff --git a/drivers/pci/of.c b/drivers/pci/of.c
>>>> index 196834ed44fe..42a5cfac2d34 100644
>>>> --- a/drivers/pci/of.c
>>>> +++ b/drivers/pci/of.c
>>>> @@ -469,6 +469,8 @@ static int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *
>>>> } else {
>>>> /* We found a P2P bridge, check if it has a node */
>>>> ppnode = pci_device_to_OF_node(ppdev);
>>>> + if (ppnode && of_node_check_flag(ppnode, OF_DYNAMIC))
>>>> + ppnode = NULL;
>>> Again, different behavior if dynamic. I'm not seeing why you need this
>>> change.
>> This change is required. For dynamic generated node, we do not generate
>> interrupt routing related properties. Thus we need to fallback to use
>> pci_swizzle_interrupt_pin(). Generating interrupt routing related
>> properties might be difficult. I think we can differ it to the future
>> patches. Or just use pci_swizzle_interrupt_pin() which is much simpler.
> I don't think we need to generate anything else in the DT. I think we
> need to break from the loop if (ppnode && of_property_present(ppnode,
> "interrupt-map")) instead.
Sure. I will use 'interrupt-map' instead.
>
>
>>>> +static int of_pci_prop_reg(struct pci_dev *pdev, struct of_changeset *ocs,
>>>> + struct device_node *np)
>>>> +{
>>>> + struct of_pci_addr_pair *reg;
>>>> + int i = 1, resno, ret = 0;
>>>> + u32 flags, base_addr;
>>>> + resource_size_t sz;
>>>> +
>>>> + reg = kcalloc(PCI_STD_NUM_BARS + 1, sizeof(*reg), GFP_KERNEL);
>>>> + if (!reg)
>>>> + return -ENOMEM;
>>>> +
>>>> + /* configuration space */
>>>> + of_pci_set_address(pdev, reg[0].phys_addr, 0, 0, 0, true);
>>>> +
>>>> + base_addr = PCI_BASE_ADDRESS_0;
>>>> + for (resno = PCI_STD_RESOURCES; resno <= PCI_STD_RESOURCE_END;
>>>> + resno++, base_addr += 4) {
>>>> + sz = pci_resource_len(pdev, resno);
>>>> + if (!sz)
>>>> + continue;
>>>> +
>>>> + ret = of_pci_get_addr_flags(&pdev->resource[resno], &flags);
>>>> + if (ret)
>>>> + continue;
>>>> +
>>>> + of_pci_set_address(pdev, reg[i].phys_addr, 0, base_addr, flags,
>>>> + true);
>>>> + reg[i].size[0] = FIELD_GET(OF_PCI_SIZE_HI, (u64)sz);
>>>> + reg[i].size[1] = FIELD_GET(OF_PCI_SIZE_LO, (u64)sz);
>>>> + i++;
>>>> + }
>>>> +
>>>> + ret = of_changeset_add_prop_u32_array(ocs, np, "reg", (u32 *)reg,
>>> I believe this should be 'assigned-addresses' rather than 'reg'. But the
>>> config space entry above does go in 'reg'.
>> Do you mean I need to add 'assigned-addresses' in this patch?
> Yes, but on further thought, I think they can just be omitted. They
> are only needed
> if we need of_pci_address_to_resource() to work.
Got it.
>
>> For 'reg', it needs to have pairs for memory space or I/O space. Here is
>> what I saw in IEEE1275:
>>
>> "In the first such pair, the phys-addr component shall be the
>> Configuration Space address of the
>> beginning of the function's set of configuration registers (i.e. the
>> rrrrrrrr field is zero) and the size component shall
>> be zero. Each additional (phys-addr, size) pair shall specify the
>> address of an addressable region of Memory Space or I/
>> O Space associated with the function. In these pairs, if the "n" bit of
>> phys.hi is 0, reflecting a relocatable address, then
>> phys.mid and phys.lo specify an address relative to the value of the
>> associated base register. In general this value will be
>> zero, specifying an address range corresponding directly to the
>> hardware's. If the "n" bit of phys.hi is 1, reflecting a nonrelocatable
>> address, then phys.mid and phys.hi specify an absolute PCI address."
> I think this is a case where true OpenFirmware and FDT differ
> slightly. In OF, the DT reflects everything the firmware discovered
> and configured. FDT is more just what's static and not discoverable.
> (Though generating nodes here is more OF like.) For example, we don't
> put the bus numbers in the DT as those are dynamic and assigned by the
> OS. The purpose of the BAR registers in reg is to define the BAR size
> (and address only if fixed). We don't need that unless what's
> discoverable is wrong and we want to override it.
Thanks for the comments. I will remove the memory and I/O pairs.
>
>
>>>> diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
>>>> index 57ddcc59af30..9120ca63a82a 100644
>>>> --- a/drivers/pci/pci-driver.c
>>>> +++ b/drivers/pci/pci-driver.c
>>>> @@ -1634,7 +1634,8 @@ static int pci_dma_configure(struct device *dev)
>>>> bridge = pci_get_host_bridge_device(to_pci_dev(dev));
>>>>
>>>> if (IS_ENABLED(CONFIG_OF) && bridge->parent &&
>>>> - bridge->parent->of_node) {
>>>> + bridge->parent->of_node &&
>>>> + !of_node_check_flag(bridge->parent->of_node, OF_DYNAMIC)) {
>>> Again, I don't think changing behavior for dynamic case is right. I
>>> haven't dug into what an ACPI+DT case would look like here. (Hint:
>>> someone that wants this merged can dig into that)
>> I think this is required. Without dynamic node, on pure DT system,
>> has_acpi_companion() will return false. Then "ret" is 0 and the
>> following iommu_device_use_default_domain() might be called.
>>
>> With dynamic node, of_dma_configure() might return error because dma
>> related properties are not generated. Thus, "ret" is none zero and the
>> following iommu_device_use_default_domain() will be skipped.
> Again, dynamic is the wrong thing to key off of. If we need
> properties, then they should be added. However, I think the host
> bridge should have what's needed. If the code needs to handle this
> case, then we need to figure out the right thing to do.
I see. I will remove this change. It is not needed for pure DT case.
Thanks,
Lizhi
>
> Rob
Powered by blists - more mailing lists