Subject: Introducing environment in autoconf(9)
To: None <email@example.com>
From: Quentin Garnier <firstname.lastname@example.org>
Date: 11/11/2005 20:19:14
Content-Type: text/plain; charset=us-ascii
(This will be longish, but I think it's something important to have.)
For quite a while now I've been playing with ACPI tables to see what
could be done with it, and how. One of the things that ACPI brings us
is the ability to correct the interrupt routing setup done (or rather,
not done) by the BIOS.
We currently have code (under PCI_INTR_FIXUP) that looks up the _PRT
tables for each PCI bus and tries to apply it. However, this is done
Firstly, it is done before we set APIC mode, which means that when we
use potentially bogus data because information usually change depending
on what we call _PIC with.
Secondly, the bus numbers on which we apply the fixups are guessed from
the ACPI table, and thus do not necessarily match the real thing,
because sometimes PCI-to-PCI bridge devices don't have a _PRT object in
the ACPI table, or you can even have devices listed with a _PRT table
even though it doesn't match actual hardware (the ACPI table I saw
that does this probably have extensions through a docking bay).
The second point is what lead me to that idea of autoconf environment
variables: we have to do the normal device probing, while still be
aware of the fact that the ACPI table is there to help us.
Currently, a child device only knows about its parent, and doesn't
actually know anything about it besides the way it got attached, through
the attachment args parameter. Configuration environment variables
will allow a device to pass information through all its children.
For example, one thing we need is to make sure we don't try probing
ISA devices before we probed all devices appearing in the ACPI table.
config_defer() is currently unable to allow that, but I've been
thinking of changing it to add a new parameter, the device after which
the deferred function should be called. Then, the acpi device would
push its struct device into the environment so that the LPC bridge
could properly defer the ISA attachment.
I came up with the following API, and as I know it might not be perfect,
I'm kindly asking for opinions about it.
Environment variables are strings associated to a void * value, which
can be NULL. There can be multiple occurrences of a variable (I will
go back to that later).
int config_env_add(const char *name, void *value);
The variable should be added to the list, but should be unique.
Therefore this function will return EEXIST if a variable with the
same name has already been defined.
int config_env_push(const char *name, void *value);
The variable should be added to the list, duplicates are
allowed. _push and _add can return ENOMEM.
int config_env_get(const char *name, void **value)
Retrieves the first available value for variable "name". The
variable is left in the environment.
int config_env_pop(const char *name, void **value)
Retrieves the first available value for variable "name". The
said occurrence of the variable is destroyed. _get and _pop
return ENONENT if the variable is not defined.
int config_env_peek(const char *name)
Returns the number of matches for variable "name". Can be 0.
void config_env_purge(const char *name)
Destroys all occurrences of variable "name".
That's half of the work though. There is another issue, being the
attachment of devices using the environment variables.
There will be two kinds of environment variables: those that pass
information through the autoconf process, and those who act a bit
like locators, except they're defined by the configuration process
instead of the properties of the hardware.
The latter class is important in the ACPI interrupt fixup problem.
The idea is that when a pci(4) device is discovered, it should
attach normally (i.e., the parent device is the same, the way it
attaches is the same), except that it should use the environment
variable that contains information about its ACPI device counterpart.
This is where config(1) has to be changed. The linked config.diff
contains all the code that makes this work, and what it does is the
following: it adds a new syntax, "reattach" that will override an
existing device attachment (the name of the struct deva is used)
provided a number of environment variables are found in the environment.
The override will only be defined if the relevant attributes are
declared by the user in the config file, and at runtime, the override
will only happen if the environment variables are defined. Another
cfattach structure will be used, and different _match and _attach
functions can be used.
I'm not including the changes to pci.c and all the code in acpi/ that
make the attachment happens, because they're not relevant to what
should be discussed first. I'm happiliy running a kernel where
pci0 attaches at acpi0, and where _PRT tables are used when attaching
the pci0 and pci1 devices. I had the changes tested by another people
who confirmed it made his laptop work.
(For the record, my own laptop doesn't need PCI_INTR_FIXUP. When ioapic
is not used, the interrupts are fubared and the ACPI table is bogus and
doesn't solve the conflicts. When ioapic is used, things are just
fine. But that's only my laptop.)
I mentioned earlier my intent to allow duplicates in the environment.
The reason I'd prefer that is the way I intend to attach CPU devices
probed through the ACPI table. I've seen several laptop where there
are multiple CPU devices in the table, yet only one non-HT non-dual
core CPU in the hardware. The mainbus would get the CPU listing from
the MADT, and push the IDs of the actually existing CPUs into the
environment, and the CPU devices would pick them up when probed, to
check their existence. But I haven't written the code to do that yet.
Kudos to those who have reached that point :)
Quentin Garnier - email@example.com - cube@NetBSD.org
"When I find the controls, I'll go where I like, I'll know where I want
to be, but maybe for now I'll stay right here on a silent sea."
KT Tunstall, Silent Sea, Eye to the Telescope, 2004.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (NetBSD)
-----END PGP SIGNATURE-----