Subject: Re: Device Properties: The Next Generation
To: None <cgd@sibyte.com, eeh@netbsd.org>
From: None <eeh@netbsd.org>
List: tech-kern
Date: 02/16/2001 20:13:48
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.
O.K.
> 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.
"Hello foot. Meet gun."
If you want to use the presence of a property as an unvalued
boolean, you need to know what you are doing and either not
specify inheritance or handle the complexities it creates.
Whiteouts just make the problem worse.
(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)...
It is a protocol violation, and the driver should error
out and fail to attach, but it should not cause a panic
(unless the system cannot operate without that driver).
But, since variable sized properties are legal this
check should be left to the requestor:
if (dev_getprop(dev, "prop", &buf, sizeof(buf)) != sizeof(buf))
panic("prop is bogus\n");
> 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.
Usually if you `dev_delprop()' you want to remove the
property on this node and allow further queries to propagate
up the tree. This is where you start getting non-intuitive
behavior.
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.
[Whiteouts could be also be implemented inside md_getprop()....]
I still don't think whiteouts are needed, and I don't think
they are worth the complexity they add.
Whiteouts are required for union mounts because you are transparently
merging multiple directory levels to look like a single level.
Here you are explicitly requesting recursive searches and have
full control over the searches yourself. It is a minor convenience
rather than a necessity as it is with union mounts.
> 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-)
Separating properties by who set them gets complicated. Especially
for queries. If you want to do this, add intermediate device nodes
just for holding properties.
>
> 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.)
(Yes, I know.)
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?)
I expect these properties to be used to propagate attachment
information. They are not designed for efficient access.
However, the uses I see for them and what they eventually
are used for may be completely different things.
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.
If the value of the property has changed, and a bus knows
it might be used by lower level drivers, it should advertise
the new property. Once again, different drivers must agree
on one protocol for those properties.
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.
If a property is advertized, anyone can traverse the tree
and read it. And whiteouts will not stop that from occurring.
And if you don't trust the drivers to behave themselves and
not zero out your root disk you should not load the drivers.
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.
I don't think this is much of an improvement. Usually a
device will do one of several types of queries:
1) I need this property from this particular node or I can't
attach.
2) I need this property or I can't attach and I don't care
where it comes from.
3) If I can get the value of this property I can enable these
neat features.
If a property is critical you will probably do a query of the
first type.
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
Actually you would.
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
Think about the order of operation: to create the new chipset
tag you need access to the parent's chipset tag. So you query
for a chipset tag. Then you create the new chipset tag. Then
you create a property associated with your device node to
advertize that tag.
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.)
Sure you would. If you export the same property that some ancestor
does, but you need access to your ancestor's property then you
query your parent for the property. (Otherwise you need to remove
your property, query yourself to get your ancestor's property, and
reinstall your property.)
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...
Why? Do you expect your parent to change its value?
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...)
These seem to be rather arbitrary distinctions. If a property
needs to be on a child node then it should be placed there. If
a child needs to query its parent then it should do so. If those
options don't work then perhaps the properties are placed on the
wrong node or incorrectly defined.
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".
Limiting inheritance to `x' number of levels does not work. A bus
driver cannot know how many levels of bridges are between it and the
end device. You would need a way to `extend' properties down another
level, which is the equivalent of just duplicating them on each level.
> 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-)
Yes, but event notification is a completely different issue. (Wasn't
there some discussion about using FreeBSD's implementation?)
> 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.
If we start handling hotplug then attach will need to be able to fail.
If the hardware was removed between probe and attach then the attach
cannot succeed. (I suppose the device could set a callout in the attach
routine to immediately call detach, and then succeed the attach, but that
starts getting silly.)
Eduardo