Subject: Re: resource allocation, pcmcia, isapnp, etc.
To: Noriyuki Soda <soda@sra.co.jp>
From: Justin T. Gibbs <gibbs@caspian.plutotech.com>
List: tech-kern
Date: 06/22/1999 22:50:22
>gibbs> Okay.  Here I certainly misunderstood your 'static configuration' 
>gibbs> concern.  I didn't even consider this because in the 'new-bus'
>gibbs> paradigm, this problem doesn't arise.
>
>Yes, new-bus completely focuses dynamic configuration, and real
>`static configuration' doesn't exist in new-bus.
>But dynamic configuration like new-bus is not needed for (e.g.) legacy
>workstations or embeded systems. For those systems, dynamic
>configuration like new-bus is merely overkill.

Although I agree that the ability to configure a system with minimal
memory requirements is important, I don't see that all of the features
of new-bus are overkill for these kinds of systems.  I believe that
new-bus can still achieve the required flexibility for these situations.

>Newconfig's goals are
>	(a) support almost completely static configuration like current
>	  NetBSD. This doesn't require inner-kernel linker and other
>	  dead loads for systems which don't need the features.

If all required modules are already in the kernel, then you have no need
for the linker in new-bus either.  I see no reason why you could not
configure a new-bus kernel without the linker.  Of course, the in-kernel
linker is only ~150K (200K if you need to be able to link in aout modules
too), so we're not talking about a lot of space anyway.

The in-kernel linker has some advantages too.  If a third party vendor
wants to give you a module to load at boot time to support some piece of
hardware you need for an install, how do they provide a 'single-user
environment' where you can run ld (the ELF version on x86 is 310K), have
access to the running kernel's image and symbol information, and still
include space for the temporarty object file ld will create?  This opens
a big space problem if your install media is a floppy, and I don't see how
you can effectively load critical modules necessary for boot with an
external linker.  Forcing the 3rd party vendor to ship a 'link-kit' which
includes the linker tools would give them a maintenance nightmare.

How does new-config address the above scenario?  With a linker in the
loader?

>gibbs> - The config file as we know it now is gone.  It is only used
>gibbs>   as a mechanism for grouping .c files into modules, indicating
>gibbs>   which modules to build, and specifying #define type module
>gibbs>   options.  No explicit bus hierarchy information or other
>gibbs>   configuration information is required at all.  The only
>gibbs>   checking required is that provided by make, the C compiler,
>gibbs>   and the linker.
>
>This means that
>	- quite simple error which can be found in config.new(8) and
>	  even old-config cannot be found in new-bus until newer
>	  kernel boots. (and, sometimes it's too late.)
>		e.g. misspelled locator name
>		     misspelled parent bus name

How does new-config know that the locator information I've provided
is incorrect given that I may choose to have 'hard-wiring' for dynamic
devices whose module I will load on demand?  Here, sanity checking
can only be performed correctly at load time.  How does new-config know
that 0x540 is not a valid port number for my 'ed0' device?  It can't
because there is a disassociation between the module that can verify
the input data and the user interface for providing that data.

With UserConfig under a fully developed new-bus, these errors cannot
happen because the module is given the ability to sanity check the
parameters that will be given to it at the time they are entered.
Granted, it would be nice to do this without booting the new kernel,
but I believe that this can be achieved by writing the instance parameter
verification portion of a module such that it could be linked into a user
land program as well as a kernel.  You want to separate this section of
your module anyway so it can be discarded/re-loaded around configuration
events.

>	- quite simple error which can be found in config.new(8) and
>	  even old-config cannot be found in new-bus until linker
>	  fails.
>		Error message from linker is not user friendly,
>		config.new(8) and old-config is far more user friendly
>		than new-bus in this point.

The only 'end-user' error possible under new-bus is forgetting to provide
a module on which other modules depend.  There is nothing preventing
us from making the error messages for required modules that are missing,
clear and understandable.  It is not as though we are dealing with a bloated
GNU ld in the kernel.

>gibbs> - Instance parameter information is saved to a special module
>gibbs>   by a userland utility after a boot to multi-user, a module is
>gibbs>   loaded, or some other event that causes persistent instance
>gibbs>   information to change (Say I'm about to add a new disk, but I
>gibbs>   want to hard wire it before I let the system see it).  In a
>gibbs>   netboot environment, you save the instance data to a module
>gibbs>   and link it into the 'kernel' module on your boot server.
>
>UserConfig and saving the result of UserConfig are certainly needed
>for NetBSD. Newconfig will implement these features.
>
>But the way you described is one of the reasons I don't like new-bus.
>I.e. New-bus heavily depends on linker set feature, and it is not so
>portable. The non-standard feature that current NetBSD MI kernel
>depends on is only 64bit integer, and I don't want to decrease
>portablity.

If you don't like linker sets (and I have my own reservations about them),
use a known module entry point to register the information.  The main thing
that linker sets buys you is the ability to easily extract the module
information without having to load the full binary into core.  You
just parse that section of the binary and you're done.

>In newconfig, configuration framework does know what should be done,
>and linker set is not needed.

Again, how you represent this data and collect it is an implementation
detail.  If you removed linker-sets from the new-bus picture, the same
data could be extracted in another way.

>To load module metainformation, root device module, and configuration
>specified by UserConfig, with third party supplied root device module,
>there are following ways:
>	1. for systems like PC or alpha, bootloader can load
>	  root device module, root device configuration and
>	  the meta information, and can pass it to kernel via memory.

So the loader acts as a linker here?

I may be confused by what you mean by a root device module.  I'm
thinking that this is the set (perhaps only one) of drivers required
to boot to a single user environment where an external linker could
be used.

>or
>	2. provide incomplete kernel image on module directory,
>	  and statically link complete kernel from
>		- the incomplete kernel image
>		- root device module
>		- root device configuration
>		- meta information from modules
>	  The other modules can be dynamically linked after system is
>	  booted. Note that newconfig's kernel module will become to
>	  be able to be linked both statically and dynamically without
>	  linker set.
>or
>	3. write necessary informations to kernels data segment
>	  by special utilities.

This is problematic for a netboot environment.  You would need to distill
this information into some format that could be later used to update the
source kernel.

>Newconfig aims all features which new-bus has about third party supplied
>drivers. Unlike new-bus, third party provides the following files
>	- kernel module itself
>	- meta information about the kernel module (i.e. "files.DEVICE")
>	- default configuration of the device
>	  (i.e. DEVICE.conf: like "fxp* at pci?")
>The installation command for kernel module gathers all meta
>informations and convert it to binary format (so, dynamic module can
>define new bus type). It also gathers all default device
>configurations and makes default dynamic kernel configuration (this
>has exactly same format as static kernel configuration). The all
>information in default dynamic configration can be overriden by user's
>default dynamic configuration file.

How do I create this environment if I don't have anything installed
yet and require this module for installation?  How do I modify module
instance parameters during a dynamic load?

>All third party supplied modules can be statically linked, too.
>And all sanity checks which currently can be done by config.new or
>old-config can be done in this case. This cannot be done by new-bus.

Under new-bus, the module contains this information and the module author
is responsible for ensuring that is is correct.  It is only in the case
where an 'as-shipped' configuration is not sufficient for load that the
user gets involved at all.  For example, look at an 'aha-isa' module under
new-bus.  The module contains an enumeration of the port numbers, dma
channels, and irqs that are acceptable for the card.  With no user
intervention, the module will look for the card at all known port numbers,
determine the drq and irq dynamically, etc.  If the user has a clone card 
that the module author doesn't know about, that resides at a strange port
location, this module won't work.  During boot or at module load time after
system boot, the user will have to either use UserConfig or a userland
utility to modify the configuration of this module.  At this point, the
module has full control over what it will accept for input.  There wasn't
an opportunity to check for errors earlier because even the author of
the module couldn't have known about this other strange device.  But, the
system has plenty of flexibility for handling even this situation.

Remember too that the goal here is to make using modules completely automatic
for the end-user.  With PnP ISA, PCI, EISA, USB, and other busses like them
coming down the pipe, we are finding more and more machines where this
is a very possible goal.  Hey, Win95 can do it, why can't we?

In the embedded world, this is even less of a problem.  The people doing
the embedding know exactly what there configuration is and the modules
they create or release for their product will know this information as
well.

>gibbs> I'm not worrying about run-time cost at all.  Configuration happens
>gibbs> so rarely that I don't think this is much of an issue at all.  The
>gibbs> main problem is that if you separate the configuration data from the
>gibbs> module, you remove some of the module author's flexibility.
>
>That's wrong. The author of the meta information is the author of the
>module. The author doesn't lose any flexibility.

And what prevents a typo in some other 'modules' config 'file' from
screwing up or conflicting with my modules data?  What guarantees the
tight association between the meta information and the module it
pertains to?  With new-bus you don't have to contend with these issues.
The packaging is implicit in the design.

>The reason why it is separated from kernel module is:
>	- to achieve sanity check on static configuration.

Which is limited at best, by its very nature.

>	- to achieve on-demand loading.

As seen by new-bus, this approach is not required to achieve on-demand
loading.

>	- to resolve attribute based dependencies which cannot be 
>	  resolved by new-bus

What prevents me from including attributes in the definition of my
module under new-bus?

>	- to use device's logical name to specify linked module,
>	  instead of device module's filename.

As mentioned before, this is also simple to solve under new-bus.

>New-bus cannot implement these features.

I still don't see this.

>gibbs> No.  Perhaps a cache of the mapping information would be nice, but you
>gibbs> can always interrate through all module files and extract their module
>gibbs> list. If you want your boot to go really fast, don't link all of your
>gibbs> modules into the auto-load directory.  If you really
>gibbs> need a module during some future boot, tell userconfig to explicitly
>gibbs> load it from the KLD directory.
>
>The way of new-bus (iterate all module files) doesn't work on machines
>which don't have enough memory.

Only the linker set information need be extracted.  This is easy to do
without loading the whole module.  The memory load should be comparable
to loading the 'files' file data as would be necessary under new-config.

>And because this information is based on module's filename, new-bus's
>dynamic configuration is not portable when module's implementation
>is changed.

I don't follow this at all.  New-bus will become filename neutral. The
only temporary association between logical module name and file name
would be needed during a load event.  In other words, during a load event,
we look inside the file to determine its logical module dependencies,
determine whether or not they are in core, and if need be, search all
other module files for the logical module names required to satisfy
the dependencies of this load.

>In newconfig, kernel configuration is always specified by device's
>logical name, thus, the configuration is more portable than new-bus.

You keep harping on this as if new-bus cannot be the same way.  It
can and will be the same way.
	
>And new-bus cannot implement real on-demand loading feature like Linux
>currently has, because it lacks meta information file.

And what prevents the userland daemon listing for hot-plug events from
extracting this information from the modules available in the system
under new-bus?  Nothing.  If you want to write this data to a cache file,
so be it, but then you need to deal with errors like meta-data files that
point to non-existent modules or are stale, etc.  I'd rather have an
environment that lacks the possibility for such errors.

>gibbs> The DMA Tag has the BUS_DMA_ALLOCNOW flag set.  This ensures
>gibbs> that either the mapping fails or is serviced instantly.
>gibbs> Remember too that this memory is the result of a
>gibbs> bus_dmamem_alloc() call which ensures that the data is mappable
>gibbs> into *bus* space with minimal cost and, in the FreeBSD
>gibbs> implementation even gives you the map to access this memory
>gibbs> (probably a bug really).
>
>Yes, there are architectures which has limited number of mapping
>hardware. I think this should be fixed for portability.

This is much the same as any system that has a limited number of
bounce buffers.  How do you deal with resource shortages without
a callback?  The above scenario is somewhat different than the
bus_dmamem_alloc case where you can dedicate a single mapping
resource for all static requests of this type.  You essentially
must provide this feature because, without kernel threads (which
would may be too expensive for some of these scenarios anyway), you
may not be able to satisfy an interrupt without the resource and
you can't wait in that context.

>gibbs> In the FreeBSD implementation you are also guaranteed that the
>gibbs> mapping of a bus_dmamem_alloc() will always succeed.
>
>Mm. Theoretically, it will fail on machines which has limited number
>of mapping hardware.

Which means that you need to provide a method for multiplexing access
to these resources in scenarios where this would be too complex or
costly to be practical.  It is one thing to require a TLB flush before
accessing device/cpu shared data structures (I'm talking about portions
of a softc, not buffer data), but forcing a queue up for every access
would be very painful.

>gibbs> Where is Jason's proposal?
>
>I meant (2) of http://mail-index.netbsd.org/tech-kern/1998/06/12/0069.html
>Perhaps Jason might have different idea now, though.

Ahh yes.  I remember that discussion.  I'm still open to this.

>gibbs> Its used for things like CODEC registration, not necessarily for the
>gibbs> end device.  It follows the approach used for many COM interfaces in
>gibbs> the Win world.
>
>Hm, thanks. Could you specify where I can find the spec. from Windows DDK?
>("COM interface" is somewhat odd for me, though... Is this really device
> driver?)

I (thankfully) existed the world of Win9X development 2.5 years ago,
so I don't have any current references.  My recollection was that this
was used for things like Direct X.

>BTW, what you pointed out doesn't prove the needs of DEVMETHOD().
>Apparently CODEC registration is not needed for almost all device
>drivers of Windows. And the current functions which is covered by
>DEVMETHOD() are not needed the feature like DEVMETHOD() in Windows.

DEVMETHOD provides a 'logical' isolation from the data structures
that make up the configuration interface.  How much 'physical'
isolation it provides depends on the implementation.  We could
easily modify DEVMETHOD to allow for even more features in this
area (such as removing allocation space for deprecated interfaces
in the default case) and only a recompile would be necessary.  This
becomes important from a 3rd party developer point of view especially
when we consciously decide to break backward binary compatibility for
some good reason.

DEVMETHOD is one example of a data structure and interface isolation
technique used in new-bus, but there are others as well.  For example,
the equivalent of 'struct device' is private to the configuration system.
In the new-config world, how would you extend 'struct device' and still
achieve binary compatibility?  For instance, you decide that, in order to
support topologies such as USB and fiber-channel, the device tree must now
become a DAG.  95% of new-config's clients could care less that this feature
is available because they can't exist in a multi-attachment scenario.  But
since this object is publicly exported, directly accessed by the driver, and
usually combined in a softc or other data structure, there is no hope for
binary compatibility if this structure changes.

>gibbs> I don't understand your performance concern.  The methods are
>gibbs> used infrequently and in scenarios where the extra bounds
>gibbs> checking overhead is insignificant.  Do we really need the '
>gibbs> Detach()' or 'Attach()' methods to be super speedy?
>
>Are Detach() and Attach() really needed to be DEVMETHOD()fied?
>I don't think so. It is quite easy to achieve binary compatibilty
>without DEVMETHOD().

Why push the implementation details of how these interfaces are
preserved and accessed down into each and every component of the
system?  Remember that DEVMETHOD() could just be the front end to
a simple function table as you often suggest is *the right* way
to do this.  In the end, the maintainer of the driver simply wants
to get that function performed and would rather spend his/her time
implementing new features, then coping with a later implementation
change.  DEVMETHOD() hides all of that.

>What really needed for binary compatibility of third party supplied
>driver is, written, well defined kernel interface which can be safely
>used by device drivers. DEVMETHOD() is wrong answer for wrong question
>like below:
>	QUESTION
>		how to achieve binary compatibility without defining
>		firm driver kernel interface.

The goal here is to ensure that the interfaces are both stable from 
the point of view of the maintainer of a module written today, yet
flexible enough to handle the modules written tomorrow.  Just take
a quick look at the src-changes list and its obvious that interfaces
are expanded or tuned all the time.  The growth of device drivers
in the tree makes it obvious that reducing the complexity of maintenance
is the only way that the developers can spend the majority of their
time focused on system improvements.

>If DEVMETHOD() is really better as you said, why don't you convert
>all interface which is used by driver -- e.g. bus_space(9), bus_dma(9),
>malloc(9), tsleep(9), wakeup(9), timeout(9) and others -- ?

I think you already know the answer.  The goal of new-bus is
to provide a flexible methodology for exporting configuration
or device specific interfaces.  The interfaces you mention are
common to almost every module of the kernel.

>soda> That's quite easy even without DEVMETHOD(),
>soda> add integer variable which represent interface version to first member
>soda> of driver's function vector.
>
>gibbs> But which interface are you talking about?
>
>Interfaces which is defined by driver kernel interface.

There may be several different interfaces a particular module
exports.  A fiber-channel card, for instance, might export an
interface for SCSI as well as one for IP functionality.  The locators
and information required for attaching to these two different stacks
may be completely unrelated, but the driver must be given the flexibility
to export both of them.

>soda> Yes, this is the reason why both newconfig and even old-config use
>soda> attribute based dependencies.
>soda> IMHO, newconfig's "attribute" is better abstraction than new-bus's
>soda> "module", because it is more general.
>
>gibbs> There is nothing that prevents a module from performing an
>gibbs> attribute based or 'name' based dependency search in new-bus
>gibbs> other than the code to do it.  I believe that Peter Wemm, once
>gibbs> over his jet-lag, is dealing with all of the loader and
>gibbs> dependency issues, so he is the one you should really talk to
>gibbs> if you want details on the work in this area.
>
>I believe if you really examine what config.new's attribute is, you
>will not call it "module".

I never did call it module.  My understanding of this functionality is
that you would like to be able to say:

	'Attach me to anyone who exports this interface'
	'Attach me to anyone who is of this class of devices'
	etc.

The attribute, or device class, or any other type of data you may
want to key of off can be stored in the module for later lookup by
the configuration system.
>
>imp> One other thing that DEVMETHOD gives you is the ability to have an
>imp> arbitrary number of function pointers in a function dispatch table and 
>imp> not have to worry about adding new functions (or even deleting old
>imp> ones).  This would allow one to add functions to the
>imp> pcmcia_chip_functions struct w/o worrying about breaking old binray
>imp> drivers.
>
>That's can be done quite easily without DEVMETHOD, see below:
>	struct DEV_functions {
>		int DEV_function_version;
>		void (*func1)(...);
>		void (*func2)(...);
>			:
>	};
>	struct DEV_softc {
>		struct device sc_dev;
>		struct DEV_functions *sc_functions;
>			:
>	};
>Note that the sc_functions member is defined as pointer to 
>struct. In this way, you can add/delete any number of functions
>without losing binary compatibility.

But you unnecessarily exposed the implementation to the module.
Struct device needs to be opaque too.

>And in reality, you cannot remove functions even with DEVMETHOD().

Not as it is currently implemented.

>If you do it, you have to add error checking to existing codes.

I believe you could do this without touching any module.

>imp> I would argue that this doesn't happen at all in new-bus.  While the
>imp> present implementation of new-bus does use BOC (bad old config) to
>imp> handle its statical linking, I believe that two issues are relevant
>imp> here.  First, is that if there were hints for the new-bus isa bus that 
>imp> stated there would be a fxp device on that bus, they would effectively 
>imp> be ignored because the DRIVER_MODULE's registration of the driver into 
>imp> the driver tree didn't add it as a child of isa. 
>
>That's worse. If a user misspelled the parent bus, the error will
>not be reported on even boot time. The user cannot understand why
>he failed in new-bus.

This is simply a growing pain.

Perhaps my perspective on this is just wrong, but I'm much more
interested in exploring the design approaches of both systems then
then the pitfalls of todays implementation.  New-bus is barely
fleshed out right now and most of the issues you raise can and
will be addressed by those working on it.  The main question I have
is will 'new-bus' or 'new-config', as envisioned by their designers,
deal with the scenarios I think are important.  From what I can
see so far, there are scenarios that new-bus deals with more elegantly
than new-config, but I'm certainly open to being convinced otherwise.

--
Justin