Subject: Re: Device Properties: The Next Generation
To: None <eeh@netbsd.org>
From: Chris G. Demetriou <cgd@sibyte.com>
List: tech-kern
Date: 02/16/2001 10:16:40
eeh@netbsd.org writes:
> So the question is: how important is inheritance during probe?
> It could be provided, but has potential complications. Or it
> can be explicitly documented not to work and suggest the use
> of the parent device pointer during probe.
I'd say that it's probably best to provide it. Simplest to understand
for the programmer, I think.
> Right, exactly. That's how I got to the question of, can you delete
> things, whiteout them, or mark a device as 'stopping' the inheritance.
>
> The way to stop inheritence is to define a property with the same
> name and different (or no) data at a lower level in the tree. Then
> dev_getprop() will return it rather than one higher up in the tree.
Different data, fine. Couple of problems with 'no data':
(1) what if what you really care about is presence or absence of a
property, i.e. it's basically an unvalued boolean? Or, is that just
not allowed? You can't delete those via no-data.
(2) it seems much easier to program for "lookup fails" than "lookup
succeeds but returns failure." As far as I can tell, any presence of
a wrong-sized property where a fixed-sized one is desired
(e.g. bus_addr_t, whatever) is a protocol violation (which probably
should cause a panic)...
> Adding whiteouts and/or `stops' will add complexity not only for
> property retrieval, both for the retrieval routines and devices
> that want to bypass those obstacles and walk the tree themselves,
> but also for property creation. If we would add whiteouts, the
> only reasonable way would be to add a flag that's passed in to
> dev_setpropt() and attached to a property that tells dev_getprop()
> if it's found to immediately terminate the property search and
> return an error. But I don't know what sort of interaction that
> would have with md_getprop().
The thing about whiteouts in this context would be, you don't ever
want to unwhiteout them, do you? so i think:
dev_delprop() would:
* delete local property value, if there is one.
* do md_getprop() and look up tree to see if one is
provided by MD code or inherited, if so
make a whiteout entry.
dev_setprop() would:
* see if there's a whiteout locally and if so
delete it
* add local property.
I don't know why it would have any strange interaction with
md_getprop. the semantics would be as you described:
search local property list
md_getprop for current device
if not root of tree, search parent (recurse).
search for local property list would see local whiteout. if it's
there, you return not found. otherwise you md_getprop(), then
recurse.
> One way to do (2) would be to provide a limited form of inheritance,
> like:
>
> parent child child child
> | props props | props props |
> | for from | for from |
> | children parent | children parent |
>
> where each | can be (perhaps "must be") a barrier that stops
> inheritance.
>
> I do not think this is needed. For instance:
Right, but is more inheritance needed? 8-)
>
> Node Properties
> --------- --------------
> Top "bus-type"="root" "power-management"="off"
> mainbus "bus-type"="mainbus"
> fhc "bus-type"="fhc" "address"=0
> upabus "bus-type"="upa" "address"=1
> pci "bus-type"="pci" "pcitag"=0xf00
> pci-bridge "pcitag"=0xbad "address"=3
> siop "bus-type"="scsi" "address"=4
> sd "address"=0 "lun"=1
>
> Using inheritance, `sd' will see that it's "address" is 0 and "lun" is 1,
> so it's disk0, LUN1. The "bus-type" it sees is "scsi". In this case, both
> "address" and "lun" will be assigned to it either by it's parent or from the
> locators. But to determine the state of "power-management" it needs to
> go all the way up to the top device node.
(BTW, 'address' is a horrific name for a property. The existing
locator names are much better.)
You could conceivably copy power-management to each bus... (There are
two sides to that coin: ease of changing at run-time, vs. local
control. Do you expect drivers to be dynamically querying properties
at run-time, or do you expect it to be primarily an attach-time
event?)
One of the concerns i have is something like:
what if a given type of device may have multiple properties which are
necessary, e.g. address1 address2 address3, only some of which are
actually provided by its parent, but some of which are provided by
previous layers of the hierarchy? I can't find a case where this is
practically a problem, but I'm not sure i've thought hard enough.
Simiarly, why should an isa or SCSI device at the bottom _ever_ have a
chance to get at the pci chipset tag of the PCI bus N layers above it?
It seems that from an abstraction point of view, it shouldn't even be
able to get at it.
Actually, interesting thought popped into my head:
Flip it around: Instead of specifying inheritance at query time,
specify it at property creation time. (below quoting your sample
names/properties, not saying that I like them 8-)
i.e., "power-management" can be inherited infinitely.
"address" can be inherited for 0 levels, i.e. only the device it's
attached to can get at it.
"pcitag" can be inherited for 1 level, i.e. current device child gets
it, & child gets it, but childrens' children do not.
Of course, this and the existing inheritance raise another issue, that
could be addressed by the partitioning approach i suggested:
pchb @ root # regular PCI HBA
pci1 @ pchb # regular pci bus on HBA
rfpchb @ pci # really-fast PCI-ish bus HBA
# instantiated on PCI.
pci2 @ rfpchb # really-fast PCI-ish bus
You might want a different PCI chipset tag between pci1 and pci2,
e.g. to handle interrupt routing differences, etc. However, to
express that in properties, you couldn't say:
pchb provide a pcichipset
rfpchb provides a pcichipset
The problem being, since rfpchb is attached at pci, it may need to use
the pcichipset provided by its parent/grandparent... and it can't
both access that and provide one to a child at once without looking
elsewhere than its own property list. (as far as I'm concerned, you
should _never_ have to e.g. examine a parent's or child's properties
directly, except in the case of crafting lists to hand off to
children.)
There's one solution that I don't like much: get the parent's value
before creating the one to pass to your children, and never look
again...
There's a solution to this with property-based inheritance amounts,
but it's kinda gross: give each device 2 levels, 'personal' & to
children. If you want to be inherited by your children only,
depending on whether you want to see the value attach to your personal
chain & say "2", or attach to your "to children" chain and say "1"...
There's also the original 'solution' to this: have rfpchb provide the
properties directly to its children (thereby wasting lots of space
with copies of properties that aren't necessary). *sigh* Back to the
future.
Maybe it's not a real problem, either. But I think that
property-based inheritance amounts are probably on the right track.
(not hard to implement either. just when recursing, keep track of how
far you've gone and if that's > the inheritance amount for the given
property, don't use it...)
I think doing inheritance based on the property, rather than the type
of call to lookup, would probably address most of my concerns that
would require "white-outs".
> Do you have any examples where you _really_ need to go over the head
> of a device's parent?
>
> Only for things like that "power-management" attribute that are globally
> applicable.
I guess you want them to be globally applicable as a default, and if
you change it at any time everybody catches it, and you only need to
change the global setting?
(how do things get notified of changes? 8-)
> If it's extremely important to you, say your register's physical
> address, and the parent has not provided it, you cannot attach.
> [So either probe should fail or we need to provide some way to
> communicate attach failure which I think we should add for cases
> like allocation failures.]
It's not clear to me that there should be the cability for an
allocation failure in attach (but that's irrelevant to this
discussion, I think 8-). There might be two kinds of failures: memory
(everything there should be done with waits being OK, and thus no
failure possible), or bus, etc., resourtes, in which case the
probe/match routine failed to do its job to verify that the resources
were available.
cgd