On Mon, Mar 11, 2019 at 04:31:18PM +0300, Sergey Miroshnichenko wrote:
> If a bridge window contains fixed areas (there are PCIe devices with
> immovable BARs located on this bus), 

I think what you mean by "immovable BARs" is "drivers that don't
support moving BARs".  I want to keep the concept of legacy and EA
resources separate because those are immovable in principle, but
drivers can always be improved.

> this window must be allocated
> within the bound memory area, limited by windows size and by address
> range of fixed resources, calculated as follows:
> 
>            | <--     bus's fixed_range_hard   --> |
>   | <--  fixed_range_hard.end - window size   --> |
>            | <--  fixed_range_hard.start + window size   --> |
>   | <--                bus's fixed_range_soft            --> |
> 
> Signed-off-by: Sergey Miroshnichenko <s.miroshniche...@yadro.com>
> ---
>  drivers/pci/setup-bus.c | 56 +++++++++++++++++++++++++++++++++++++++++
>  include/linux/pci.h     |  4 ++-
>  2 files changed, 59 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
> index a1fd7f3c5ea8..f4737339d5ec 100644
> --- a/drivers/pci/setup-bus.c
> +++ b/drivers/pci/setup-bus.c
> @@ -1809,6 +1809,61 @@ static enum enable_type pci_realloc_detect(struct 
> pci_bus *bus,
>  }
>  #endif
>  
> +static void pci_bus_update_fixed_range_soft(struct pci_bus *bus)
> +{
> +     struct pci_dev *dev;
> +     struct pci_bus *parent = bus->parent;
> +     int idx;
> +
> +     list_for_each_entry(dev, &bus->devices, bus_list)
> +             if (dev->subordinate)
> +                     pci_bus_update_fixed_range_soft(dev->subordinate);
> +
> +     if (!parent || !bus->self)
> +             return;
> +
> +     for (idx = 0; idx < ARRAY_SIZE(bus->fixed_range_hard); ++idx) {
> +             struct resource *r;
> +             resource_size_t soft_start, soft_end;
> +             resource_size_t hard_start = bus->fixed_range_hard[idx].start;
> +             resource_size_t hard_end = bus->fixed_range_hard[idx].end;
> +
> +             if (hard_start > hard_end)
> +                     continue;
> +
> +             r = bus->resource[idx];
> +
> +             soft_start = hard_end - resource_size(r) + 1;
> +             soft_end = hard_start + resource_size(r) - 1;
> +
> +             if (soft_start > hard_start)
> +                     soft_start = hard_start;
> +
> +             if (soft_end < hard_end)
> +                     soft_end = hard_end;
> +
> +             list_for_each_entry(dev, &parent->devices, bus_list) {
> +                     struct pci_bus *sibling = dev->subordinate;
> +                     resource_size_t s_start, s_end;
> +
> +                     if (!sibling || sibling == bus)
> +                             continue;
> +
> +                     s_start = sibling->fixed_range_hard[idx].start;
> +                     s_end = sibling->fixed_range_hard[idx].end;
> +
> +                     if (s_start > s_end)
> +                             continue;
> +
> +                     if (s_end < hard_start && s_end > soft_start)
> +                             soft_start = s_end;
> +             }
> +
> +             bus->fixed_range_soft[idx].start = soft_start;
> +             bus->fixed_range_soft[idx].end = soft_end;
> +     }
> +}
> +
>  /*
>   * first try will not touch pci bridge res
>   * second and later try will clear small leaf bridge res
> @@ -1847,6 +1902,7 @@ void pci_assign_unassigned_root_bus_resources(struct 
> pci_bus *bus)
>       /* Depth first, calculate sizes and alignments of all
>          subordinate buses. */
>       __pci_bus_size_bridges(bus, add_list);
> +     pci_bus_update_fixed_range_soft(bus);
>  
>       /* Depth last, allocate resources and update the hardware. */
>       __pci_bus_assign_resources(bus, add_list, &fail_head);
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 7a4d62d84bc1..75a56db73ad4 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -574,9 +574,11 @@ struct pci_bus {
>  
>       /*
>        * If there are fixed resources in the bridge window, the hard range
> -      * contains the lowest and the highest addresses of them.
> +      * contains the lowest and the highest addresses of them, and this
> +      * bridge window must reside within the soft range.
>        */
>       struct resource fixed_range_hard[PCI_BRIDGE_RESOURCE_NUM];
> +     struct resource fixed_range_soft[PCI_BRIDGE_RESOURCE_NUM];
>  
>       struct pci_ops  *ops;           /* Configuration access functions */
>       struct msi_controller *msi;     /* MSI controller */
> -- 
> 2.20.1
> 

Reply via email to