Subject: Re: resource allocation, pcmcia, isapnp, etc.
To: Warner Losh <imp@harmony.village.org>
From: Noriyuki Soda <soda@sra.co.jp>
List: tech-kern
Date: 06/23/1999 05:41:36
soda> For example, a static configuration like "fxp0 at isa? port 0x308 irq 5"
soda> makes a error on both newconfig and old-config, because fxp cannot be
soda> attached to isa bus. This error cannot be caught by new-bus, because
soda> the bus hierarchy information is embeded in DRIVER_MODULE() and not
soda> available on static configuration.
soda> 
soda> This is one of most serious design flaws of new-bus. It is obvious that
soda> this information should not be embeded in C source.

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.

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.
	(b) support completely dynamic configuration like new-bus.
	(c) support partially dynamic and partially static configuration.

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
	- 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.

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.

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

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.
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.

And of course, on the systems like workstation, root device is
provided by workstation vendor (not third party), thus, there is no
need to use dynamically loaded root device module. Statically linked
root device is just fine for those systems.

gibbs> New-bus is actually a very bad name for what 'new-bus' is
gibbs> supposed to achieve.  The goal is to handle not only hardware
gibbs> configuration, but the configuration of any type of module you,
gibbs> I, or some 3rd party developer can think up.

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.

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.

gibbs> Take the SCSI subsystem as an example.  I'd love to allow people to add
gibbs> quirk entries from userconfig.  How would you do this using newconfig?

We are currently discussing two candidates of the implementation of
device specific options. It is certainly can be implemented.

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.
The reason why it is separated from kernel module is:
	- to achieve sanity check on static configuration.
	- to achieve on-demand loading.
	- to resolve attribute based dependencies which cannot be 
	  resolved by new-bus
	- to use device's logical name to specify linked module,
	  instead of device module's filename.
New-bus cannot implement these features.

soda> To achieve on-demand loading, mapping information from driver logical
soda> name to driver module file name is needed for dynamic loader.
soda> Apparently, this information cannot be stored in driver's module
soda> itself. Thus, the dogma of new-bus ("What you need is only driver
soda> module itself") doesn't work.
soda> Some kinds of "meta file" is needed anyway.

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

Newconfig works well on small memory machines.
In newconfig, kernel configuration is always specified by device's
logical name, thus, the configuration is more portable than new-bus.

And new-bus cannot implement real on-demand loading feature like Linux
currently has, because it lacks meta information file.

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.

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.

soda> Please note that PCI device might need bounce buffering on alpha

gibbs> and x86 (remember that 36bit addressing on high end Intel servers)

Yes, I know. Almost all commercial UNIX on x86 support large memory.
The reason why I specified alpha is currently neither FreeBSD nor NetBSD
support it. :-)

soda> To fix above problem, there are two ways.

soda> 1. keep FreeBSD's bus_dma(9) API, and add confirmation which guarantees
soda>   that the callback is called.

gibbs> This is given based on the definition of the tag.

Hm, yes, you can do it with ahc->shared_data_dmat and other DMA tags
to fix this problem. But I hope the following way.

soda> 2. revert specification of the API to NetBSD's, and add callback API
soda>   which is proposed by jason.

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.

soda> Thus, as far as I know, both Win9X and WinNT don't have feature like
soda> DEVMETHOD() for dynamic loaded device driver, and don't have
soda> performance penalty.

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?)

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.

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().

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.

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 -- ?

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.

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".

imp> Also, the information is located with the driver, rather than in a
imp> central files* file.  This allows that informtaion to be updated
imp> dynamically (which covers the static case).

In dynamic configuration for newconfig, the meta information can be
updated dynamically as new-bus does.

imp> If a vendor wanted to distribute a config.new driver, that vendor
imp> would need to provide patches to the files* files.

That's simply wrong. It doesn't need to patch the files.

imp> I think that we disagree on this, except for the slight performance
imp> penalty (which I agree is present, but likely not a significant source
imp> of slowdown).  The DEVMETHOD stuff insultates changes to the interface
imp> (specifically additions) from the drivers.

That's wrong. DEVMETHOD() doesn't provide any meaningful features.
All features of DEVMETHOD can be implemented without it.

soda> There is no problem about the interface additions in simple function
soda> vector without DEVMETHOD().

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.

And in reality, you cannot remove functions even with DEVMETHOD().
If you do it, you have to add error checking to existing codes.

soda> For example, a static configuration like "fxp0 at isa? port
soda> 0x308 irq 5" makes a error on both newconfig and old-config,
soda> because fxp cannot be attached to isa bus. This error cannot be
soda> caught by new-bus, because the bus hierarchy information is
soda> embeded in DRIVER_MODULE() and not available on static
soda> configuration.
soda> This is one of most serious design flaws of new-bus. It is
soda> obvious that this information should not be embeded in C source.

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.

imp> Second, if you were authoring a static linking tool, and some
imp> user specified that as a hint, then that tool could detect that,
imp> with the modules specified, there was no way for fxp driver to
imp> attach to the isa bus.

How does the tool detect that? By scanning binary object?
That's most insufficient and unreliable way.
Newconfig's way is sufficient and reliable.

soda> In new-bus with dynamic linking, users have to know driver's file name
soda> (to load it dynamically), and it's logical name (to specify
soda> configuration hint).
soda> In other words, new-bus uses different model of kernel configuration
soda> between static configuration and dynamic configuration.

imp> This is true in the present state of things.  You will have to load
imp> fxp.ko (or mondo-ethernet.ko, which has several drivers including fxp) 
imp> to get the fxp driver.  However, the decoupling of filename from
imp> driver name allows for colocation of drivers.

And it requires separated meta information file as newconfig does.
--
soda