On Wed, Jun 10, 2015 at 10:28 AM, Alexander Holler [off-list ref] wrote:
Am 10.06.2015 um 09:30 schrieb Linus Walleij:
quoted
i2c host comes out, probes the regulator driver, regulator driver
probes and then the regulator_get() call returns.
This requires instrumentation on anything providing a resource
to another driver like those I mentioned and a lot of overhead
infrastructure, but I think it's the right approach. However I don't
know if I would ever be able to pull that off myself, I know talk
is cheap and I should show the code instead.
You would end up with the same problem of deadlocks as currently, and you
would still need something ugly like the defered probe brutforce to avoid
them.
Sorry I don't get that. Care to elaborate on why?
Yours,
Linus Walleij
From: Alexander Holler <hidden> Date: 2015-06-11 10:17:48
Am 11.06.2015 um 10:12 schrieb Linus Walleij:
On Wed, Jun 10, 2015 at 10:28 AM, Alexander Holler [off-list ref] wrote:
quoted
Am 10.06.2015 um 09:30 schrieb Linus Walleij:
quoted
quoted
i2c host comes out, probes the regulator driver, regulator driver
probes and then the regulator_get() call returns.
This requires instrumentation on anything providing a resource
to another driver like those I mentioned and a lot of overhead
infrastructure, but I think it's the right approach. However I don't
know if I would ever be able to pull that off myself, I know talk
is cheap and I should show the code instead.
You would end up with the same problem of deadlocks as currently, and you
would still need something ugly like the defered probe brutforce to avoid
them.
Sorry I don't get that. Care to elaborate on why?
Because loading/initializing on demand doesn't give you any solved order
of drivers to initialize. And it can't because it has no idea about the
requirements of other drivers. The reason why it might work better in
the case of the tegra is that it might give you another initialization
order than the one which is currently choosen, which, by luck, might be
a better one.
But maybe I missed something, I haven't looked at the patches at all.
But just loading on demand, can't magically give you a working order of
drivers to initialize. E.g. how do you choose the first driver to
initialize?
Regards,
Alexander Holler
From: Alexander Holler <hidden> Date: 2015-06-11 11:24:42
Am 11.06.2015 um 12:17 schrieb Alexander Holler:
Am 11.06.2015 um 10:12 schrieb Linus Walleij:
quoted
On Wed, Jun 10, 2015 at 10:28 AM, Alexander Holler
[off-list ref] wrote:
quoted
Am 10.06.2015 um 09:30 schrieb Linus Walleij:
quoted
quoted
i2c host comes out, probes the regulator driver, regulator driver
probes and then the regulator_get() call returns.
This requires instrumentation on anything providing a resource
to another driver like those I mentioned and a lot of overhead
infrastructure, but I think it's the right approach. However I don't
know if I would ever be able to pull that off myself, I know talk
is cheap and I should show the code instead.
You would end up with the same problem of deadlocks as currently, and
you
would still need something ugly like the defered probe brutforce to
avoid
them.
Sorry I don't get that. Care to elaborate on why?
Because loading/initializing on demand doesn't give you any solved order
of drivers to initialize. And it can't because it has no idea about the
requirements of other drivers. The reason why it might work better in
the case of the tegra is that it might give you another initialization
order than the one which is currently choosen, which, by luck, might be
a better one.
But maybe I missed something, I haven't looked at the patches at all.
But just loading on demand, can't magically give you a working order of
drivers to initialize. E.g. how do you choose the first driver to
initialize?
Other problems you will run into are time constraints and multithreaded
drivers.
E.g. we all should know how tricky it sometimes is to avoid deadlocks.
And with loading on demand, you are extending this problem over the
initialization of maybe a whole bunch of other drivers which might be
started by calling one function of another driver. And a function call
might need a very long time to finish during which an unpredictable
amount of things may happen.
It would make me wonder if that will end up with a good, usable and as
simple as possible solution.
Regards,
Alexander Holler
From: Alexander Holler <hidden> Date: 2015-06-11 11:49:45
Am 11.06.2015 um 13:24 schrieb Alexander Holler:
Am 11.06.2015 um 12:17 schrieb Alexander Holler:
quoted
Am 11.06.2015 um 10:12 schrieb Linus Walleij:
quoted
On Wed, Jun 10, 2015 at 10:28 AM, Alexander Holler
[off-list ref] wrote:
quoted
Am 10.06.2015 um 09:30 schrieb Linus Walleij:
quoted
quoted
i2c host comes out, probes the regulator driver, regulator driver
probes and then the regulator_get() call returns.
This requires instrumentation on anything providing a resource
to another driver like those I mentioned and a lot of overhead
infrastructure, but I think it's the right approach. However I don't
know if I would ever be able to pull that off myself, I know talk
is cheap and I should show the code instead.
You would end up with the same problem of deadlocks as currently, and
you
would still need something ugly like the defered probe brutforce to
avoid
them.
Sorry I don't get that. Care to elaborate on why?
Because loading/initializing on demand doesn't give you any solved order
of drivers to initialize. And it can't because it has no idea about the
requirements of other drivers. The reason why it might work better in
the case of the tegra is that it might give you another initialization
order than the one which is currently choosen, which, by luck, might be
a better one.
But maybe I missed something, I haven't looked at the patches at all.
But just loading on demand, can't magically give you a working order of
drivers to initialize. E.g. how do you choose the first driver to
initialize?
Other problems you will run into are time constraints and multithreaded
drivers.
E.g. we all should know how tricky it sometimes is to avoid deadlocks.
And with loading on demand, you are extending this problem over the
initialization of maybe a whole bunch of other drivers which might be
started by calling one function of another driver. And a function call
might need a very long time to finish during which an unpredictable
amount of things may happen.
It would make me wonder if that will end up with a good, usable and as
simple as possible solution.
Besides that instrumenting every call to another driver in order to fix
a onetime operation (the initialization) sounds like an enormous
overhead. Initialization is done pnly once, regardless how long a system
runs, but the instrumentation to fix this onetime operation would slow
down the operation during the whole runtime of a system.
I don't think this is what should be done.
On Thu, Jun 11, 2015 at 12:17 PM, Alexander Holler [off-list ref] wrote:
Am 11.06.2015 um 10:12 schrieb Linus Walleij:
quoted
On Wed, Jun 10, 2015 at 10:28 AM, Alexander Holler [off-list ref]
wrote:
quoted
quoted
You would end up with the same problem of deadlocks as currently, and you
would still need something ugly like the defered probe brutforce to avoid
them.
Sorry I don't get that. Care to elaborate on why?
Because loading/initializing on demand doesn't give you any solved order of
drivers to initialize. And it can't because it has no idea about the
requirements of other drivers. The reason why it might work better in the
case of the tegra is that it might give you another initialization order
than the one which is currently choosen, which, by luck, might be a better
one.
But maybe I missed something, I haven't looked at the patches at all. But
just loading on demand, can't magically give you a working order of drivers
to initialize. E.g. how do you choose the first driver to initialize?
So the current patch set introduces dependencies (just for device tree)
and Tomeu is working on a more generic dependency approach for
any HW description.
The first driver to initialize will be as usual the first one in the list for
that initlevel, then walking up the initilevels.
However if any driver runs into a resource roadblock it will postpone
and wait for dependencies to probe first.
Certainly it is possible to create deadlocks in this scenario, but the
scope is not to create an ubreakable system.
Yours,
Linus Walleij
On Wed, Jun 10, 2015 at 10:28 AM, Alexander Holler [off-list ref] wrote:
quoted
Am 10.06.2015 um 09:30 schrieb Linus Walleij:
quoted
quoted
i2c host comes out, probes the regulator driver, regulator driver
probes and then the regulator_get() call returns.
This requires instrumentation on anything providing a resource
to another driver like those I mentioned and a lot of overhead
infrastructure, but I think it's the right approach. However I don't
know if I would ever be able to pull that off myself, I know talk
is cheap and I should show the code instead.
You would end up with the same problem of deadlocks as currently, and you
would still need something ugly like the defered probe brutforce to avoid
them.
Sorry I don't get that. Care to elaborate on why?
Because loading/initializing on demand doesn't give you any solved order
of drivers to initialize. And it can't because it has no idea about the
requirements of other drivers.
So, this is only about ordering device probing. All built-in drivers
have already registered themselves by when we start probing.
The reason why it might work better in
the case of the tegra is that it might give you another initialization
order than the one which is currently choosen, which, by luck, might be
a better one.
Note that this series was also tested on iMX.6, Exynos and OMAP4.
But maybe I missed something, I haven't looked at the patches at all.
It's a really small patchset :)
19 files changed, 130 insertions(+), 45 deletions(-)
Thanks,
Tomeu
But just loading on demand, can't magically give you a working order of
drivers to initialize. E.g. how do you choose the first driver to
initialize?
Regards,
Alexander Holler
From: Alexander Holler <hidden> Date: 2015-06-11 16:40:29
Am 11.06.2015 um 14:30 schrieb Linus Walleij:
On Thu, Jun 11, 2015 at 12:17 PM, Alexander Holler [off-list ref] wrote:
quoted
Am 11.06.2015 um 10:12 schrieb Linus Walleij:
quoted
On Wed, Jun 10, 2015 at 10:28 AM, Alexander Holler [off-list ref]
wrote:
quoted
quoted
quoted
You would end up with the same problem of deadlocks as currently, and you
would still need something ugly like the defered probe brutforce to avoid
them.
Sorry I don't get that. Care to elaborate on why?
Because loading/initializing on demand doesn't give you any solved order of
drivers to initialize. And it can't because it has no idea about the
requirements of other drivers. The reason why it might work better in the
case of the tegra is that it might give you another initialization order
than the one which is currently choosen, which, by luck, might be a better
one.
But maybe I missed something, I haven't looked at the patches at all. But
just loading on demand, can't magically give you a working order of drivers
to initialize. E.g. how do you choose the first driver to initialize?
So the current patch set introduces dependencies (just for device tree)
and Tomeu is working on a more generic dependency approach for
any HW description.
The first driver to initialize will be as usual the first one in the list for
that initlevel, then walking up the initilevels.
However if any driver runs into a resource roadblock it will postpone
and wait for dependencies to probe first.
Certainly it is possible to create deadlocks in this scenario, but the
scope is not to create an ubreakable system.
IAnd what happens if you run into a deadlock? Do you print "you've lost,
try changing your kernel config" in some output hidden by a
splash-screen? ;)
That sounds like the fun with duck typed languages where you have to
test any and every possible screnario (something which is almost
impossible) in order to not run into something unexpected.
Anyway, have fun, good luck.
Alexander Holler
On Thu, Jun 11, 2015 at 6:40 PM, Alexander Holler [off-list ref] wrote:
Am 11.06.2015 um 14:30 schrieb Linus Walleij:
quoted
Certainly it is possible to create deadlocks in this scenario, but the
scope is not to create an ubreakable system.
IAnd what happens if you run into a deadlock? Do you print "you've lost, try
changing your kernel config" in some output hidden by a splash-screen? ;)
Sorry it sounds like a blanket argument, the fact that there are
mutexes in the kernel makes it possible to deadlock, it doesn't
mean we don't use mutexes. Some programming problems are
just like such.
Yours,
Linus Walleij
From: Alexander Holler <hidden> Date: 2015-06-12 11:19:48
Am 12.06.2015 um 09:25 schrieb Linus Walleij:
On Thu, Jun 11, 2015 at 6:40 PM, Alexander Holler [off-list ref] wrote:
quoted
Am 11.06.2015 um 14:30 schrieb Linus Walleij:
quoted
quoted
Certainly it is possible to create deadlocks in this scenario, but the
scope is not to create an ubreakable system.
IAnd what happens if you run into a deadlock? Do you print "you've lost, try
changing your kernel config" in some output hidden by a splash-screen? ;)
Sorry it sounds like a blanket argument, the fact that there are
mutexes in the kernel makes it possible to deadlock, it doesn't
mean we don't use mutexes. Some programming problems are
just like such.
I'm not talking about specific deadlocks through mutexes. I'm talking
about what happens when driver A needs driver B which needs driver A.
How do you recognise and handle that with your instrumented on-demand
device initialization? Such a circular dependency might happen by just
adding a new fucntion call or by changing the kernel configuration. And
with the on-demand stuff, the possibility that the developer introducing
this new (maybe optional) call will never hit such a circular dependency
is high. So you will end up with a never ending stream of problem
reports whenever someone introduced such a circular dependecy without
having noticed it.
And to come back to specific deadlocks, if you are extending function
calls from something former simple to something which might initialize a
whole bunch of drivers, needing maybe seconds, I wouldn't say this is a
blanket argument, but a real thread.
Alexander Holler
From: Alexander Holler <hidden> Date: 2015-06-12 11:36:44
Am 12.06.2015 um 13:19 schrieb Alexander Holler:
Am 12.06.2015 um 09:25 schrieb Linus Walleij:
quoted
On Thu, Jun 11, 2015 at 6:40 PM, Alexander Holler
[off-list ref] wrote:
quoted
Am 11.06.2015 um 14:30 schrieb Linus Walleij:
quoted
quoted
Certainly it is possible to create deadlocks in this scenario, but the
scope is not to create an ubreakable system.
IAnd what happens if you run into a deadlock? Do you print "you've
lost, try
changing your kernel config" in some output hidden by a
splash-screen? ;)
Sorry it sounds like a blanket argument, the fact that there are
mutexes in the kernel makes it possible to deadlock, it doesn't
mean we don't use mutexes. Some programming problems are
just like such.
I'm not talking about specific deadlocks through mutexes. I'm talking
about what happens when driver A needs driver B which needs driver A.
How do you recognise and handle that with your instrumented on-demand
device initialization? Such a circular dependency might happen by just
adding a new fucntion call or by changing the kernel configuration. And
with the on-demand stuff, the possibility that the developer introducing
this new (maybe optional) call will never hit such a circular dependency
is high. So you will end up with a never ending stream of problem
reports whenever someone introduced such a circular dependecy without
having noticed it.
And to come back to specific deadlocks, if you are extending function
calls from something former simple to something which might initialize a
whole bunch of drivers, needing maybe seconds, I wouldn't say this is a
blanket argument, but a real thread.
Keep in mind, that the possibility that a function call ends up with
initializing a whole bunch of other drivers, is not determined
statically, but depends on the configuration and runtime behaviour of
the actual system the on-demand stuff actually happens.
E.g. if driver A is faster one system that driver B, the whole bunch of
drivers might become initialized by a call in driver A. But if driver B
was faster on the developers system (or the system is configured to
first init driver B), than the whole bunch of drivers might have become
initialized by driver B on the developers system. Thus he never might
have hit a possible problem when the whole bunch of drivers got
initialized in driver A.
That means it isn't always a good idea to create dynamic systems (like
on-demand device initialization), because it's very hard to foresee and
correctly handle their runtime behaviour.
From: Alexander Holler <hidden> Date: 2015-06-13 18:28:01
Am 12.06.2015 um 13:36 schrieb Alexander Holler:
Am 12.06.2015 um 13:19 schrieb Alexander Holler:
quoted
Am 12.06.2015 um 09:25 schrieb Linus Walleij:
quoted
On Thu, Jun 11, 2015 at 6:40 PM, Alexander Holler
[off-list ref] wrote:
quoted
Am 11.06.2015 um 14:30 schrieb Linus Walleij:
quoted
quoted
Certainly it is possible to create deadlocks in this scenario, but the
scope is not to create an ubreakable system.
IAnd what happens if you run into a deadlock? Do you print "you've
lost, try
changing your kernel config" in some output hidden by a
splash-screen? ;)
Sorry it sounds like a blanket argument, the fact that there are
mutexes in the kernel makes it possible to deadlock, it doesn't
mean we don't use mutexes. Some programming problems are
just like such.
I'm not talking about specific deadlocks through mutexes. I'm talking
about what happens when driver A needs driver B which needs driver A.
How do you recognise and handle that with your instrumented on-demand
device initialization? Such a circular dependency might happen by just
adding a new fucntion call or by changing the kernel configuration. And
with the on-demand stuff, the possibility that the developer introducing
this new (maybe optional) call will never hit such a circular dependency
is high. So you will end up with a never ending stream of problem
reports whenever someone introduced such a circular dependecy without
having noticed it.
And to come back to specific deadlocks, if you are extending function
calls from something former simple to something which might initialize a
whole bunch of drivers, needing maybe seconds, I wouldn't say this is a
blanket argument, but a real thread.
Keep in mind, that the possibility that a function call ends up with
initializing a whole bunch of other drivers, is not determined
statically, but depends on the configuration and runtime behaviour of
the actual system the on-demand stuff actually happens.
E.g. if driver A is faster one system that driver B, the whole bunch of
drivers might become initialized by a call in driver A. But if driver B
was faster on the developers system (or the system is configured to
first init driver B), than the whole bunch of drivers might have become
initialized by driver B on the developers system. Thus he never might
have hit a possible problem when the whole bunch of drivers got
initialized in driver A.
That means it isn't always a good idea to create dynamic systems (like
on-demand device initialization), because it's very hard to foresee and
correctly handle their runtime behaviour.
And because you've said that "problem space is a bit convoluted" and I
disagree, here's a summary from my point of view:
1. All the necessary information (dependencies between drivers) already
exists at compile time. The set of dependencies between drivers might
become smaller by configuration, but will not become larger. So there
should be NO need to collect them at runtime, e.g. by instrumenting
function calls. I've described the problems I see with that above. I've
choosen DT as source of dependencies because it offers an easy
accessible and almost complete set of dependencies. I just had to add
some type information to the dtb in order to identify the dependencies
(phandles). But other ways to collect the dependencies would work too.
Even the most simple way to add a static list of dependencies to each
driver (which later on might be automated by some more clever stuff than
adding them manually) would do the trick.
2. The problem to sort a set of nodes (drivers) with dependencies is
solved since a long time and almost any developers uses it regularly in
form of make. And everyone who used make -jN knows that the possible
parallel initialization of drivers I've talked about, is already solved too.
3. In order to initialize the drivers in some specific order, their
initcalls must be identified. I've offered a possible solution to that
without much changes, but many other, even better ways, are possible
too. It just depends on how much you want to change and on how much of
these changes you will be able to feed into mainline kernel (which
depends on your connections/relations inside the core kernel crew). E.g.
instead of still just relying on one-dimensional arrays with (anonymous)
pointers to initcalls, a multidimensional array of initcalls and
drivername (and maybe more information) might be thinkable.
4. x86/amd64/ACPI-people, so most longtime and core kernel maintainers
obviously don't have much interest until you've solved 1. in a way they
can use too. So the necessary changes for 2. or 3. will have a big
hurdle to take if 1. isn't solved usable for them too.
On Sat, Jun 13, 2015 at 8:27 PM, Alexander Holler [off-list ref] wrote:
And because you've said that "problem space is a bit convoluted" and I
disagree, here's a summary from my point of view:
1. All the necessary information (dependencies between drivers) already
exists at compile time. The set of dependencies between drivers might become
smaller by configuration, but will not become larger. So there should be NO
need to collect them at runtime, e.g. by instrumenting function calls.
I think you arrived at the core of the crux here.
When we look up a resource provided from another driver, e.g. from
regulator_get(), clk_get(), pinctrl_get(), gpiod_get() etc - the dependency
is resolved by looking in a cross-reference table for either a struct device*
pointer or a string, an index, or both or all three. Examples:
struct regulator *regulator_get(struct device *dev, const char *id);
struct clk *clk_get(struct device *dev, const char *id);
struct gpio_desc *__must_check __gpiod_get(struct device *dev,
const char *con_id,
enum gpiod_flags flags);
(...)
(*_index() variants exist on some of the resource retrieveal
functions.)
struct device * is the device requesting the resource, con_id
is the string name of the resource on the provider side. This is all
solved by looking in cross reference tables. ONE way of resolving
that cross reference is to look into the device tree or the ACPI table.
But for the board file case, this is resolved at runtime by the cross
reference table, registered with calls such as gpiod_add_lookup_table().
It is true that in the theoretical sense, all of this exist at compile time
especially if you can parse something like a device tree and
figure out what struct device * nodes will correspond to the struct
device_node:s in it. For ACPI I guess a similar procedure is viable.
Problem: this requires the kernel compile to know exactly *which* device tree
or ACPI table it is going to boot on. The expressed goal of device tree
and ACPI is to have *ONE* kernel booting several device trees.
Here your approach stops short: you are suggesting instrumenting
the kernel at compile time to one single device tree or ACPI table.
But we never know really what device tree or ACPI table will be used.
This just cannot be done at compile time for that reason alone.
Example: in boot case (A) the regulator may be provided by regulator
"foo" driver on an i2c bus. But in boot case (B) the very same regulator
may be provided by regulator "bar" on an SPI bus. These are very
real usecases, for example for drivers/net/ethernet/smsc/smsc911x.c,
will get regulators from the most diverse places depending on what
device tree is used.
For board files, it is neither possible in theory: you need to compile the
code to figure out the struct device * provider, and/or the string name
of the providing device (.name field in struct device for the provider)
to resolve dependencies at compile time.
For the board file case, resolving dependencies at compile time will
require a quite complex two-stage rocket: compile the code to
get resources out, then recompile with known resources.
I guess your suggested approach then need to introduce a special
build tool to order the initcalls accordingly.
Again this will fall short if you don't know at compile time exactly
*which* board file will be executed.
So the only practical way to solve this at compile time is to predict
an initcall ordering sequence for all possible boot paths, compile in
all of them, and choose the right one at boot. But the number of boot
paths is equal to the number of device trees / ACPI tables or
board files supported, and that space is uncontrolled and ordered
infinite.
Basically I think the root problem with your approach is that you
assume we know what hardware we will boot on at compile time. We
discarded that development path years ago. We have no clue, this
is resolved at runtime. Alas, people still create super-optimized
systems using exactly this knowledge, but it is not our main target
here, it is a special optimization case.
Yours,
Linus Walleij
From: Alexander Holler <hidden> Date: 2015-06-15 09:43:25
Am 15.06.2015 um 10:58 schrieb Linus Walleij:
On Sat, Jun 13, 2015 at 8:27 PM, Alexander Holler [off-list ref] wrote:
quoted
And because you've said that "problem space is a bit convoluted" and I
disagree, here's a summary from my point of view:
1. All the necessary information (dependencies between drivers) already
exists at compile time. The set of dependencies between drivers might become
smaller by configuration, but will not become larger. So there should be NO
need to collect them at runtime, e.g. by instrumenting function calls.
I think you arrived at the core of the crux here.
I've hoped so, that's why I've written it.
I guess your suggested approach then need to introduce a special
build tool to order the initcalls accordingly.
Again this will fall short if you don't know at compile time exactly
*which* board file will be executed.
I've just tried to describe the facts in order to make the problem space
more clear, because, as said, I don't think it's convoluted.
Besides that, I didn't want to suggest anything else other than what
I've already posted working patches for. What I've mentioned as possible
other solutions above is stuff which might be possible too in order to
give some starting points for people which are searching another
solution. But I wouldn't have written my patches as they are, if I would
think there is another more easier solution.
And of course, there is still a bit to resolve at runtime, even in the
DT case (look at the "compatible" attribute). But there is already a
runtime solution to find the right driver (in case of DT) and I haven't
mentioned it in order to no confuse people again. Mentioning every
little detail doesn't make sense if you want to describe something
understandable (which is what I've tried).
So the only practical way to solve this at compile time is to predict
an initcall ordering sequence for all possible boot paths, compile in
all of them, and choose the right one at boot. But the number of boot
paths is equal to the number of device trees / ACPI tables or
board files supported, and that space is uncontrolled and ordered
infinite.
You just need one working ordered sequence which includes all options.
This one will work for all others too.
Basically I think the root problem with your approach is that you
assume we know what hardware we will boot on at compile time. We
Totally wrong. If you assume that I assume this, than either I was
totally unable to describe something clearly, or you were unable or
unwilling to understand what I've written. And as the result is the
same, we don't need to find out which was reason.
Anyway, have fun. I'm quitting the discussion here as I don't have any
business with the kernel and already decided some time again to not post
patches anymore as it seems to be a waste of my (and maybe others) time.
Regards,
Alexander Holler