Subject: Re: resource allocation, pcmcia, isapnp, etc.
To: Justin T. Gibbs <gibbs@narnia.plutotech.com>
From: Noriyuki Soda <soda@sra.co.jp>
List: tech-kern
Date: 06/20/1999 23:42:20
Hi, Justin.
I owe you about your ahc driver, and I'm positive about your CAM
(though I think if CAM is integrated to NetBSD, co-existing with
julian SCSI is required to support transition), but I have different
opinion about new-bus/newconfig thing. Please let me describe it.

> > As far as you will support static configuration, the information
> > represented by DRIVER_MODULE() is also needed for static
> > configuration. But because DRIVER_MODULE() is embeded in C source, the
> > information cannot be used by static configuration.
> 
> The information in DRIVER_MODULE() is available if you are statically
> linked or not.  It is equivalent, as I understand the proposed (or
> perhaps implemented) changes to config.new, to a binary version of
> the 'files' file.  Can you be more specific about why you feel this
> mechanism is inadequate for the statically linked case?  I have yet
> to dynamically load a single KLD under new-bus, but all of my device
> drivers still seem to work just fine. 8-)

For example, a static configuration like "fxp0 at isa? port 0x308 irq 5"
makes a error on both newconfig and old-config, because fxp cannot be
attached to isa bus. This error cannot be caught by new-bus, because
the bus hierarchy information is embeded in DRIVER_MODULE() and not
available on static configuration.

This is one of most serious design flaws of new-bus. It is obvious that
this information should not be embeded in C source.

> > In newconfig, the information is represented by "files*" file,
> > thus it can be used by both static configuration and dynamic configuration.
> 
> Only once the 'files*' file is presented in a binary format (or converted
> to a binary format from the loader, etc.) 

Binary conversion has to be done only once when new driver is
installed, (this is only needed once in driver development phase,
because the meta information will not be changed.)
and the conversion is done in only one command without any argument,
so you don't have to care about this cost seriously.

> From the discussions about this issue at USENIX, it seemed that both
> sides realize the requirement for a binary representation that works
> for both static and dynamic configuration.  The thought from the
> new-bus camp has always been that the format for that data should be
> the same in all scenarios and be tightly coupled (i.e. imbedded) to
> the binary module.  This is the rational behind DRIVER_MODULE().

As described above "fxp0 at isa?" example , the information embeded in
DRIVER_MODULE() should be accessed from static configuration.

> > Because first implementation of config_detach() has been known since
> > 1996. (far before new-bus is started)
> 
> Right.  The unit numbering thing is an implementation detail that
> can be solved in either framework.  I'm not familiar with how you
> plan to remove a driver entry from the cf database under config.new,
> but I'm sure it could be done with the appropriate tweaks to the
> cf data structures.  Driver instance removal is clearly possible
> today.

Yes, you can look at it on kern/subr_autoconf.c:config_detach() of
NetBSD-1.4.

> > This supports on-demand loading of device drivers which cannot be
> > implemented by new-bus.
> 
> I don't follow your last comment.  Can you describe a scenario where
> new-bus would fail?  I understand your concern over the static versus
> dynamic module location problem, but this is an implementation flaw,
> not a design flaw in new-bus that is being rectified as we speak.

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

On both old-config and newconfig with both static and dynamic linking,
users don't have to know driver file name, they just have to specify
"fxp* at pci?", and corresponding modules are loaded automatically,
if it is not loaded yet.

In new-bus with static linking, this might be same. (Though, I'm not
sure, because new-bus currently depends on old-config about static
configuration.)
In new-bus with dynamic linking, users have to know driver's file name
(to load it dynamically), and it's logical name (to specify
configuration hint).
In other words, new-bus uses different model of kernel configuration
between static configuration and dynamic configuration.

> > It is problem of FreeBSD's callback interface of bus_dma(9) and it's
> > usage. It can be fixed by changing it's usage, but I think NetBSD's
> > interface is better than fixing usage.
> 
> Is the concern here that a callback could occur after an unload event?

Yes, that is one of the problems, but not only that.
Please look at ahc_init() in your aic7xxx.c, there is a following statement:
	bus_dmamap_load(ahc->shared_data_dmat, ahc->shared_data_dmamap,
			ahc->qoutfifo, driver_data_size,
			ahcdmamapcb, &ahc->shared_data_busaddr, /*flags*/0);
This statement schedules ahcdmamapcb() callback to initialize
ahc->shared_data_busaddr.
Almost 250 lines later of ahc_init(), there is a following statement:
	physaddr = ahc->shared_data_busaddr;
This statement access ahc->shared_data_busaddr which is initialized
by ahcdmamapcb().

But there is no guarantee that the ahcdmamapcb() is called between
these two statements. Please note that PCI device might need bounce
buffering on alpha, and ahc_init() might be called after userland
is started if it is dynamically loaded.

To fix above problem, there are two ways.
1. keep FreeBSD's bus_dma(9) API, and add confirmation which guarantees
  that the callback is called.
2. revert specification of the API to NetBSD's, and add callback API
  which is proposed by jason.
Both of two ways do work. But I hope FreeBSD choose 2. because
	- for most cases, NetBSD's API is more convenient from
	  driver writer's viewpoint.
	- compatibility with NetBSD.

> >> : DEVMETHOD() is worst way to achieve compatible device drivers.
> >> : Any other operating systems which allow dynamic loading device driver
> >> : has such feature? No, there isn't. It is not needed. It is slow.
> 
> Actually yes.  Win9X exports several interfaces using a similar method.

On Win9X, device's own method is implemented by
1. a callback function registered by CM_Register_Driver() or
  other registration functions.
2. DRP_aer (asynchronous event procedure) of DRP (driver registration
  packet) structure.
Both the callback function and DRP_aer are simple function.

On WinNT, device's own method is implemented by MajorFunction[] member 
of DRIVER_OBJECT, and it is simple function vector.

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

Please specify more precisely about what you are talking about.

> > There is no problem about the interface additions in simple function
> > vector without DEVMETHOD().
> 
> And how do you safely determine at run time that a module you interface
> with supports a particular method?  For instance, I'm a 3rd party vendor
> of an in-kernel module that needs to talk to several ethernet drivers.
> Some of these drivers may have been compiled before certain features
> were added to the 'ethernet driver' interface.  As a good vendor,
> I want to deal with both 'old' ethernet drivers and new ones, but I need
> to know which ones provide the new functionality.  This is part of 
> what DEVMOTHOD() hopes to achieve.

That's quite easy even without DEVMETHOD(),
add integer variable which represent interface version to first member
of driver's function vector.
then, the third party vendor can choose what method (in function
vector) should be used with the driver by the version number.

Actually this way is far more convenient than DEVMEHTOD().
Because if the vendor use DEVMETHOD(), they have to call new interface
first, then check whether the new interface works or not, and then
they have to choose which interface should be used.
If the vendor use the version variable describe above, they can
choose the interface without calling it.

> Certainly, if you want to do it all by hand, then so be it.  The
> whole point of the interface files is to automate the process of
> defining interfaces that provide binary compatibility, some amount
> of safety for interface version missmatch between modules and, with
> just a bit of tweaking to the interface generator, can add interface
> versioning without touching any clients of the code.  It doesn't
> sound like you are arguing that the things the interface generator
> is providing are unnecessary in all cases, but you are unhappy with
> the implementation.

I agree that DEVMETHOD() might be usefull for some (but not all)
cases, like vnode_if of vfs/vnode ops. But then DEVMETHOD() can be
used in newconfig, too. :-)

> > For example, if you will change the name of the backend driver, or
> > if you will split backend driver into two part, aic_pccard.ko will 
> > no longer work.
> > Newconfig doesn't have this problem.
> 
> File based dependencies don't work for lots of reasons.
	:
      [snip]
	:
> > How does KLD know that aic backend is already statically linked?
> 
> It looks up the module name in a linker set list of modules already
> present in-core.  KLD knows how to dynamically add entries to linker
> sets during a dynamic load, so this just falls out.  The current problem
> is that the module name is based on the file where it came from (e.g.
> 'kernel' for a statically linked object) and it's quite obvious why
> this currently loses.

Yes, this is the reason why both newconfig and even old-config use
attribute based dependencies.
IMHO, newconfig's "attribute" is better abstraction than new-bus's
"module", because it is more general.
--
soda