On Wed, Dec 28, 2011 at 06:35:55PM +1300, Alexey Korolev wrote:
> All devices behind a bridge need to have all their regions consecutive and
> not overlapping with all the normal memory ranges.
> Since prefetchable memory is described by one record, we must avoid the 
> situations
> when 32bit and 64bit prefetchable regions are present within one secondary 
> bus.

How do we avoid this? Assume we have two devices:
a 32 bit and a 64 bit one, behind a bridge.
There are two main things we can do:
1. Make the 64 bit device only use the low 32 bit
2. Put the 32 bit one in the non-prefetcheable range

1 probably makes more sense for small BARs
2 probably makes more sense for large ones

Try also looking at e.g. linux bus scanning code for more ideas.

Another thing I don't see addressed here is that support for 64 bit
ranges is I think optional in the bridge.

> 
> Signed-off-by: Alexey Korolev<alexey.koro...@endace.com>

Whitespace is corrupted: checkyour mail setup?
There should be spaces around operators:
a < b, I see a< b. Sometimes a<  b (two spaces after).

> ---
>  src/pciinit.c |   69 +++++++++++++++++++++++++++++++++++++++-----------------
>  1 files changed, 48 insertions(+), 21 deletions(-)
> 
> diff --git a/src/pciinit.c b/src/pciinit.c
> index a574e38..92942d5 100644
> --- a/src/pciinit.c
> +++ b/src/pciinit.c
> @@ -17,6 +17,7 @@
> 
>  #define PCI_BRIDGE_IO_MIN      0x1000
>  #define PCI_BRIDGE_MEM_MIN   0x100000
> +#define PCI_BRIDGE_MEM_MAX   0x80000000
> 
>  enum pci_region_type {
>      PCI_REGION_TYPE_IO,
> @@ -45,6 +46,7 @@ struct pci_bus {
>          s64 base;
>          s64 bases[32 - PCI_MEM_INDEX_SHIFT];
>      } r[PCI_REGION_TYPE_COUNT];
> +    int is64;
>      struct pci_device *bus_dev;
>  };
> 
> @@ -369,6 +371,26 @@ static void pci_bios_bus_reserve(struct pci_bus *bus, 
> int type, u32 size)
>          bus->r[type].max = size;
>  }
> 
> +static void pci_bios_secondary_bus_reserve(struct pci_bus *parent,
> +                                           struct pci_bus *s, int type)
> +{
> +    u32 limit = (type == PCI_REGION_TYPE_IO) ?
> +        PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN;
> +
> +    if (s->r[type].sum>  PCI_BRIDGE_MEM_MAX) {
> +        panic("Size: %08x%08x is too big\n",
> +                (u32)s->r[type].sum, (u32)(s->r[type].sum>>32));
> +    }
> +    s->r[type].size = (u32)s->r[type].sum;
> +    if (s->r[type].size<  limit)
> +        s->r[type].size = limit;
> +    s->r[type].size = pci_size_roundup(s->r[type].size);
> +
> +    pci_bios_bus_reserve(parent, type, s->r[type].size);
> +    dprintf(1, "    size: %x, type %s\n",
> +                s->r[type].size, region_type_name[type]);
> +}
> +
>  static void pci_bios_check_devices(struct pci_bus *busses)
>  {
>      dprintf(1, "PCI: check devices\n");
> @@ -392,8 +414,10 @@ static void pci_bios_check_devices(struct pci_bus 
> *busses)
>              pci_bios_bus_reserve(bus, type, size);
>              pci->bars[i].addr = val;
>              pci->bars[i].size = size;
> -            if (type == PCI_REGION_TYPE_PREFMEM_64)
> +            if (type == PCI_REGION_TYPE_PREFMEM_64) {
> +                bus->is64 = 1;
>                  i++;
> +            }
>          }
>      }
> 
> @@ -404,22 +428,21 @@ static void pci_bios_check_devices(struct pci_bus 
> *busses)
>          if (!s->bus_dev)
>              continue;
>          struct pci_bus *parent =&busses[pci_bdf_to_bus(s->bus_dev->bdf)];
> +
> +        if (s->r[PCI_REGION_TYPE_PREFMEM_64].sum&&

Space before && here and elsewhere.

> +                   s->r[PCI_REGION_TYPE_PREFMEM].sum) {
> +           panic("Sparse PCI prefmem regions on the bus %d\n", 
> secondary_bus);
> +        }
> +
> +        dprintf(1, "PCI: secondary bus %d\n", secondary_bus);
>          int type;
>          for (type = 0; type<  PCI_REGION_TYPE_COUNT; type++) {
> -            u32 limit = (type == PCI_REGION_TYPE_IO) ?
> -                PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN;
> -            s->r[type].size = s->r[type].sum;
> -            if (s->r[type].size<  limit)
> -                s->r[type].size = limit;
> -            s->r[type].size = pci_size_roundup(s->r[type].size);
> -            pci_bios_bus_reserve(parent, type, s->r[type].size);
> -        }
> -        dprintf(1, "PCI: secondary bus %d sizes: io %x, mem %x, prefmem 
> %x\n",
> -                secondary_bus,
> -                s->r[PCI_REGION_TYPE_IO].size,
> -                s->r[PCI_REGION_TYPE_MEM].size,
> -                s->r[PCI_REGION_TYPE_PREFMEM].size);
> -    }
> +            if ((type == PCI_REGION_TYPE_PREFMEM_64&&  !s->is64) ||
> +                (type == PCI_REGION_TYPE_PREFMEM&&  s->is64))
> +                continue;

Can't figure this out. What does this do?

> +            pci_bios_secondary_bus_reserve(parent, s, type);
> +       }
> +   }
>  }
> 
>  #define ROOT_BASE(top, sum, max) ALIGN_DOWN((top)-(sum),(max) ?: 1)
> @@ -507,14 +530,17 @@ static void pci_bios_map_devices(struct pci_bus *busses)
>          struct pci_bus *parent =&busses[pci_bdf_to_bus(bdf)];
>          int type;
>          for (type = 0; type<  PCI_REGION_TYPE_COUNT; type++) {
> +            if ((type == PCI_REGION_TYPE_PREFMEM_64&&  !s->is64) ||
> +                (type == PCI_REGION_TYPE_PREFMEM&&  s->is64))
> +                continue;
>              s->r[type].base = pci_bios_bus_get_addr(
>                  parent, type, s->r[type].size);
>          }
>          dprintf(1, "PCI: init bases bus %d (secondary)\n", secondary_bus);
>          pci_bios_init_bus_bases(s);
> 
> -        u32 base = s->r[PCI_REGION_TYPE_IO].base;
> -        u32 limit = base + s->r[PCI_REGION_TYPE_IO].size - 1;
> +        s64 base = s->r[PCI_REGION_TYPE_IO].base;
> +        s64 limit = base + s->r[PCI_REGION_TYPE_IO].size - 1;
>          pci_config_writeb(bdf, PCI_IO_BASE, base>>  PCI_IO_SHIFT);
>          pci_config_writew(bdf, PCI_IO_BASE_UPPER16, 0);
>          pci_config_writeb(bdf, PCI_IO_LIMIT, limit>>  PCI_IO_SHIFT);
> @@ -525,12 +551,13 @@ static void pci_bios_map_devices(struct pci_bus *busses)
>          pci_config_writew(bdf, PCI_MEMORY_BASE, base>>  PCI_MEMORY_SHIFT);
>          pci_config_writew(bdf, PCI_MEMORY_LIMIT, limit>>  PCI_MEMORY_SHIFT);
> 
> -        base = s->r[PCI_REGION_TYPE_PREFMEM].base;
> -        limit = base + s->r[PCI_REGION_TYPE_PREFMEM].size - 1;
> +        type = s->is64 ? PCI_REGION_TYPE_PREFMEM_64 : 
> PCI_REGION_TYPE_PREFMEM;
> +        base = s->r[type].base;
> +        limit = base + s->r[type].size - 1;
>          pci_config_writew(bdf, PCI_PREF_MEMORY_BASE, base>>  
> PCI_PREF_MEMORY_SHIFT);
>          pci_config_writew(bdf, PCI_PREF_MEMORY_LIMIT, limit>>  
> PCI_PREF_MEMORY_SHIFT);
> -        pci_config_writel(bdf, PCI_PREF_BASE_UPPER32, 0);
> -        pci_config_writel(bdf, PCI_PREF_LIMIT_UPPER32, 0);
> +        pci_config_writel(bdf, PCI_PREF_BASE_UPPER32, base>>  32);
> +        pci_config_writel(bdf, PCI_PREF_LIMIT_UPPER32, limit>>  32);
>      }
> 
>      // Map regions on each device.
> -- 
> 1.7.5.4
> 

Reply via email to