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