On Wed, Dec 3, 2008 at 7:46 AM, Myles Watson mylesgw@gmail.com wrote:
-----Original Message----- From: Marc Jones [mailto:marcj303@gmail.com] Sent: Tuesday, December 02, 2008 7:52 PM To: Myles Watson Cc: ron minnich; Rudolf Marek; Coreboot Subject: Re: [coreboot] Resource Allocation discussion
On Tue, Dec 2, 2008 at 3:23 PM, Myles Watson mylesgw@gmail.com wrote:
-----Original Message----- From: ron minnich [mailto:rminnich@gmail.com] Sent: Tuesday, December 02, 2008 2:51 PM To: Myles Watson Cc: Marc Jones; Rudolf Marek; Coreboot Subject: Re: [coreboot] Resource Allocation discussion
On Tue, Dec 2, 2008 at 11:33 AM, Myles Watson mylesgw@gmail.com
wrote:
Do we want to take fixed resources into account in the allocator?
I would think so.
I would too, but v2 didn't and did pretty well. I'm interested to see
an
idea for the resource allocation algorithm that allocates from largest
to
smallest resource, except when it's skipping fixed resources.
I think it's doable, but nothing like what we have.
That surprises me. I thought it does, which is how/why you can get rid of DEVICE_MEM_HIGH. Otherwise you would clobber the ROM and the APIC.
You're right. I think it's broken. That's why right now I'm setting the base to 0xfc000000 manually. Thanks for pointing it out.
I'd assumed that resource_max took fixed resources into account, but it doesn't. All resource_max does is align the resource based on its limit.
So maybe we need to traverse the tree looking for fixed spaces, and constrain the domain's resource limit and base. That wouldn't be too hard. What I was saying would be hard is interleaving fixed resources with movable resources. In other words, if we put the VGA ROM between the two APIC allocations to save space. I think that's too ugly.
I'll add a traversal to the tree that doesn't ignore fixed resources.
A question before the code: 1. Can anyone enumerate all the fixed resources that should be included in QEMU? Currently I have: - DRAM (first 640K and 0xc0000-TOP-768K) Is this necessary? - I/O first 0x400 in southbridge - VGA 0xa0000-0xc0000 - APIC at 0xfec00000 and 0xfee00000 - ROM at 0xfff80000
Side note: Only the lowest and highest fixed addresses matter in my code. The others get ignored. I think it's too much pain to try to interleave them to use the space between 0xfee00000 and 0xfff80000, for example.
All right. I've added code that traverses each domain looking for fixed resources. Here's the pseudo code:
For each domain: call avoid_fixed_resources(domain_dev)
avoid_fixed_resources(dev) initialize limits to maximum size initialize the limits to dev's resources limits call constrain_resources(dev, limits) update dev's resources
constrain_resources(dev, limits) for each child call constrain_resources(child, limits) for each fixed resource if limits contain resource update limits to exclude resource (largest space possible)
And here's the code. It's not a diff because it's all new. struct constraints { struct resource pref, io, mem; };
static void constrain_resources(struct device *dev, struct constraints* limits) { struct device *child; struct resource *res; struct resource *lim; int i;
#ifdef CONFIG_PCI_64BIT_PREF_MEM #define MEM_MASK (IORESOURCE_PREFETCH | IORESOURCE_MEM) #else #define MEM_MASK (IORESOURCE_MEM) #endif #define IO_MASK (IORESOURCE_IO) #define PREF_TYPE (IORESOURCE_PREFETCH | IORESOURCE_MEM) #define MEM_TYPE (IORESOURCE_MEM) #define IO_TYPE (IORESOURCE_IO)
/* Descend into every child and look for fixed resources. */ for (child=dev->link[0].children; child; child = child->sibling) { constrain_resources(child, limits); for (i = 0; i<child->resources; i++) { res = &child->resource[i]; if (!(res->flags & IORESOURCE_FIXED)) continue; /* Choose larger space: above or below fixed resources. */
/* PREFETCH */ if ((res->flags & MEM_MASK) == PREF_TYPE) { lim = &limits->pref; /* Is it already outside the limits? */ if ((res->base + res->size -1) < lim->base || res->base > lim->limit) continue; /* Is the space above larger? */ if ((lim->limit - (res->base + res->size -1)) > (res->base - lim->base)) lim->base = res->base + res->size; else lim->limit = res->base -1; }
/* MEM */ if ((res->flags & MEM_MASK) == MEM_TYPE) { lim = &limits->mem; /* Is it already outside the limits? */ if ((res->base + res->size -1) < lim->base || res->base > lim->limit) continue; /* Is the space above larger? */ if ((lim->limit - (res->base + res->size -1)) > (res->base - lim->base)) lim->base = res->base + res->size; else lim->limit = res->base -1; }
/* I/O */ if ((res->flags & IO_MASK) == IO_TYPE) { lim = &limits->io; /* Is it already outside the limits? */ if ((res->base + res->size -1) < lim->base || res->base > lim->limit) continue; /* Is the space above larger? */ if ((lim->limit - (res->base + res->size -1)) > (res->base - lim->base)) lim->base = res->base + res->size; else lim->limit = res->base -1; } } } }
static void avoid_fixed_resources(struct device *dev) { struct constraints limits; struct resource *res; int i;
/* Initialize constraints to maximum size. */
limits.pref.base = 0; limits.pref.limit = 0xfffffffffffffffULL; limits.io.base = 0; limits.io.limit = 0xfffffffffffffffULL; limits.mem.base = 0; limits.mem.limit = 0xfffffffffffffffULL;
/* Initialize the limits from the device's resources. */ for (i = 0; i<dev->resources; i++) { res = &dev->resource[i];
/* PREFETCH */ if ((res->flags & MEM_MASK) == PREF_TYPE && res->limit < limits.pref.limit ) limits.pref.limit = res->limit; /* MEM */ if ((res->flags & MEM_MASK) == MEM_TYPE && res->limit < limits.mem.limit ) limits.mem.limit = res->limit; /* I/O */ if ((res->flags & IO_MASK) == IO_TYPE && res->limit < limits.io.limit ) limits.io.limit = res->limit; }
constrain_resources(dev, &limits);
for (i = 0; i<dev->resources; i++) { res = &dev->resource[i]; /* Update the device's resources with new limits. */
/* PREFETCH */ if ((res->flags & MEM_MASK) == PREF_TYPE) { /* Is the resource outside the limits? */ if ( limits.pref.base > res->base ) res->base = limits.pref.base; if ( res->limit > limits.pref.limit ) res->limit = limits.pref.limit; }
/* MEM */ if ((res->flags & MEM_MASK) == MEM_TYPE) { /* Is the resource outside the limits? */ if ( limits.mem.base > res->base ) res->base = limits.mem.base; if ( res->limit > limits.mem.limit ) res->limit = limits.mem.limit; }
/* I/O */ if ((res->flags & IO_MASK) == IO_TYPE) { /* Is the resource outside the limits? */ if ( limits.io.base > res->base ) res->base = limits.io.base; if ( res->limit > limits.io.limit ) res->limit = limits.io.limit; } } }
Thanks, Myles