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/20/1999 11:32:49
>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)

Certainly the transition problem for CAM in NetBSD is a different beast
than it was in FreeBSD where the number of drivers we currently need
to support is much smaller.  There is also the ATAPI issue (ATAPI should
be integrated under CAM, but I haven't found the time to do it yet).
If you'd like to discuss these issues, shoot me some private email, or
if there is general interest, start the conversation here under a different
subject line.

>, but I have different
>opinion about new-bus/newconfig thing. Please let me describe it.

Please.  USENIX proved that most of the *issues* about new-bus vs. newconfig
were really just misunderstandings of both parties intentions and design
goals.

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

Okay.  Here I certainly misunderstood your 'static configuration' concern.
I didn't even consider this because in the 'new-bus' paradigm, this problem
doesn't arise.

In an ideal world, the way you perform configuration of a module embedded
in the KLD called 'kernel' or any other module loaded after system boot
would be the same.  The belief in the new-bus camp is that there really
isn't anything that prevents you from doing this.  In a new-bus world:

- The config file as we know it now is gone.  It is only used as a mechanism
  for grouping .c files into modules, indicating which modules to build, and
  specifying #define type module options.  No explicit bus hierarchy
  information or other configuration information is required at all.  The only
  checking required is that provided by make, the C compiler, and the linker.

- When you load a new module after system boot:
	o the module is linked into the kernel
	o the module's method for instance parameter registration is invoked.
	o the user is provided with a mechanism for creating per instance
	  parameter modifications.
	o the module is run.  "Run" may mean different things for different
	  types of modules.

- When you boot the system, 'UserConfig' will provide the same features.
  The only difference here is that you won't be using a syscal interface
  to access module intance parameter information.

- Instance parameter information is saved to a special module by a userland
  utility after a boot to multi-user, a module is loaded, or some other
  event that causes persistent instance information to change (Say I'm about
  to add a new disk, but I want to hard wire it before I let the system see
  it).  In a netboot environment, you save the instance data to a module and
  link it into the 'kernel' module on your boot server.

The idea here is that the module knows best, and config cannot know all of the
dependencies for all types of modules (new fs, a new network stack, etc.) so
the interface must be rich enough for the modules to export this information
themselves and allow them to sanity check user parameters.

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

Take the SCSI subsystem as an example.  I'd love to allow people to add
quirk entries from userconfig.  How would you do this using newconfig?
In newbus, the tape driver module would export a global configuration item
using simple text, enum, and integer field primitives (so the userconfig
UI or a userland utility can format and display the data) to allow this
to be configured.  Since the module is responsible for sanity checking
any input (perhaps using some libkern functionality to do the common stuff)
the functionality is fully self contained.  A 3rd party driver developer should
have the flexibility to do these kinds of things without forcing an update
of anything but their own module.

There are certainly problems with this kind of approach, and many of the
implementation assumptions I've made above are my own (others following
the new-bus discussions may have different ideas here).  But I think that
the above discription gives you an idea of the types of things new-bus
is trying to achieve.

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

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

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

No.  Perhaps a cache of the mapping information would be nice, but you
can always interrate through all module files and extract their module
list.  If you want your boot to go really fast, don't link all of your
modules into the auto-load directory.  If you really
need a module during some future boot, tell userconfig to explicitly
load it from the KLD directory.

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

This is true today, but this is an implementation issue, certainly not
part of our end strategy.

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

The DMA Tag has the BUS_DMA_ALLOCNOW flag set.  This ensures that either
the mapping fails or is serviced instantly.  Remember too that this memory
is the result of a bus_dmamem_alloc() call which ensures that the data is
mappable into *bus* space with minimal cost and, in the FreeBSD implementation
even gives you the map to access this memory (probably a bug really).
In the FreeBSD implementation you are also guaranteed that the mapping of
a bus_dmamem_alloc() will always succeed.

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

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

>, and ahc_init() might be called after userland
>is started if it is dynamically loaded.

Certainly, and since the FreeBSD bus_dma implementation allocates individual
bounce pages, getting low memory pages is not as hard as it would be if
we required the entire transaction to be bounced to contiguous low memory
pages.

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

This is given based on the definition of the tag.

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

Where is Jason's proposal?  I'll be the first to admit that FreeBSD's
API is missing features in the NetBSD API (mostly implemented after
I pulled this stuff into FreeBSD), and I have not had the time to
articulate in a formal spec the way that the current API works.  If
there is again interest in merging the two APIs, I will find the time
on my side to facilitate this effort.

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

Its used for things like CODEC registration, not necessarily for the
end device.  It follows the approach used for many COM interfaces in
the Win world.

I don't understand your performance concern.  The methods are used 
infrequently and in scenarios where the extra bounds checking overhead
is insignificant.  Do we really need the 'Detach()' or 'Attach()' methods
to be super speedy?

>That's quite easy even without DEVMETHOD(),
>add integer variable which represent interface version to first member
>of driver's function vector.

But which interface are you talking about?  A single driver may export
several different interfaces.  The main point is to hide from
the module just how the version information is stored and accessed.

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

There is nothing that prevents a module from performing an attribute
based or 'name' based dependency search in new-bus other than the code
to do it.  I believe that Peter Wemm, once over his jet-lag, is dealing
with all of the loader and dependency issues, so he is the one you should
really talk to if you want details on the work in this area.

--
Justin