-
Notifications
You must be signed in to change notification settings - Fork 6.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC][WIP] Make DEVICE init and device_get dt aware #20253
Conversation
Benefits of this approach:
|
Some checks failed. Please fix and resubmit. pylint issues
checkpatch (informational only, not a failure)
Tip: The bot edits this comment instead of posting a new one, so you can check the comment's history to see earlier messages. |
c5bf8d6
to
81c03e6
Compare
I'm still not convinced this is something desirable. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Too bad I'm not there; this is exactly the sort of thing I'm interested in.
In principle I think this is great. I'd intended to use the ordinal generated by #19454 for this, with the thought of providing a lookop table rather than external name, but this works. A benefit of using the ordinal is that we could put all the device instance records into a linker section in dependency order, which could simplify initialization.
One concern is that the generated names like DT_INST_0_NORDIC_NRF_SAADC_ZDID
intrude on the binding namespace, since it conflicts with a binding property named ZDID
. We've made progress to eliminating that by using prefixes instead; it's sad to introduce a new case.
To @erwango's point I think keeping the label
property is fine: it should just be used for its defined purpose "human readable string describing a device" rather than as a handle that identifies the device within a registry. Though I don't know how we deal with all the device_get_binding(DT_INST_0_FOO_LABEL)
uses that already exist.
scripts/dts/gen_defines.py
Outdated
@@ -101,6 +101,9 @@ def main(): | |||
write_existence_flags(node) | |||
|
|||
out_dev(node, "ZDID", node_to_zdid[node]) | |||
print("#ifndef _ASMLANGUAGE", file=header_file) | |||
print("extern struct device __device_{};".format(node_to_zdid[node]), file=header_file) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice if this include some identification:
#ifndef _ASMLANGUAGE
extern struct device __device_4; /* SILABS_GETCKO_I2C#0 */
#endif
or something else so we could catch the declaration name using grep. Given the amount of commenting in the generated file this looks bare without the identification.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will need @ulfalizer help with that, but should be doable.
@@ -26,7 +32,7 @@ void main(void) | |||
|
|||
printk("Starting i2c scanner...\n"); | |||
|
|||
i2c_dev = device_get_binding(I2C_DEV); | |||
i2c_dev = device_get_dt_binding(SILABS_GECKO_I2C, 0); | |||
if (!i2c_dev) { | |||
printk("I2C: Device driver not found.\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's a case where @erwango's point becomes highly relevant. When I see code like this I usually change it to:
printk("I2C: Device driver %s not found.\n", I2C_DEV);
(and have done so in this exact code multiple times, though never pushed it up). A human can read "Device driver I2C_0 not found" and realize that I2C_1
should have been specified instead.
Can we add API to do something like:
printk("I2C: Device driver %s not found.\n", device_get_dt_label(SILABS_GECKO_I2C, 0));
scripts/dts/gen_defines.py
Outdated
@@ -101,6 +107,7 @@ def main(): | |||
write_existence_flags(node) | |||
|
|||
out_dev(node, "ZDID", node_to_zdid[node]) | |||
print("extern struct device __device_{};".format(node_to_zdid[node]), file=dev_extern_file) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice if this include some identification:
...
extern struct device __device_4; /* SILABS_GETCKO_I2C#0 */
or something else so we could catch the declaration name using grep. I'm imagining cases where I have a pointer, look it up in a linker map, and want to know what it belongs to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some nits. Need to look into how this stuff works atm in more detail.
|
||
node_to_zdid[node] = zdid | ||
zdid = zdid + 1 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could move into a separate function (init_zdid()
or init_dev_ids()
or the like). Would be nice if we could keep main()
about the same size forever.
The application can reference via instance, alias, path. I just did it via instance in here. so we can have:
|
Seems pretty neat. Guess the aliases generated by Still wonder if there's a nicer name than |
I don't think this scales, peripheral address is not used in ref manuals (it is not even available) nor available on most of board documentation. User have to go and check:
So we need to define an alias for each peripheral instance... Not sure this scales either. Anyway we can use node name (ie phandle)? |
The vision for this that I discussed with Kumar was that "it's just a pointer dereference!" makes phandles "just work": from Edit: to clarify, |
The node name isn't the phandle, which isn't text; the generic syntax is:
The label is what's used as the reference in things like Nomenclature nit-picking aside, I agree that |
This makes sense. Something to consider is that AFAIK to this point the only way to get a
|
Agreed, the intent was the assign the numbers in that order, I was just being quick with giving some numbering system to show something work. But totally agree this should be
Fair, I thought about that and agree. This will get fixed.
The hope is to remove the string at some point since it would reduce footprint. |
I was thinking of a Kconfig option that would cause the value of the |
That would allow us to use the ordinal ( Then there's still a barrier of going through |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure we want to separate the base identifier of a device and its instance number.
First because it will require to deprecate device_get_binding(), second because its replacement will require 2 parameters (ok that's a minor issue, but it adds up a bit of complexity: before 1 param, now 2... to do the same thing).
include/device.h
Outdated
@@ -9,6 +9,7 @@ | |||
#define ZEPHYR_INCLUDE_DEVICE_H_ | |||
|
|||
#include <kernel.h> | |||
#include <dts_device_extern.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not instead including it as the other generated_dts_*.h files?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I follow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
including it in generated_dts_board.h
I find it awkward to have this new generated header in a public header file such as device.h
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's an issue in that generated_dts_board.h is just defines, putting externs
in there causes issues with the linker scripts as they include and I think utilize defines from generated_dts_board.h
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can't we #ifndef _LINKER_SCRIPT
our way around that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or advance to putting them all into a linker section in ZDID order, and indexing into the resulting array with ZDID. A benefit of that is that the opaque handle could be a u16_t
, we could retain device_get_binding(ID)
with a change in argument signature (or a parallel function with different name), and we don't have to worry as much about people trying to use uninitialized devices just because they got the pointer to one somehow. Then there's just:
extern struct device *__devices[];
#define device_get_dt_binding(BLAH) __devices[MAGIC_GET_ZDID(BLAH)]
somewhere.
(I assume one ordinal reserved for "no-such-device", and no Zephyr image would have more than 65534 devices. 254 seems too small.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can't we
#ifndef _LINKER_SCRIPT
our way around that?
possibly, didn't know this ifdef existed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
possibly, didn't know this ifdef existed.
The name is just a suggestion, I'm saying we can make sure a macro is defined only when running cpp over the ld scripts and use that here
#define device_get_dt_binding_zdid(zdid) _CONCAT(&__device_, zdid) | ||
|
||
#define device_get_dt_binding(name, inst) \ | ||
device_get_dt_binding_zdid(DT_INST_##inst##_##name##_ZDID) \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hum, if there was an issue with you approach that would be this: the need to replace device_get_binding() by something like above.
Can't we find a way to avoid that? (I fully realize if there is a solution, it will require all your patches to be reworked.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
avoid it how?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
first, what would be better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
avoid it how?
Exactly my question :)
I understand the idea behind this patches, however it's changing how user will get the bindings. It could be done directly with a static string being the same as the dts node label ("SPI_0" for instance). That was simple.
Also doing it that way was closely down to the board the user is using. He probably does not know which controller runs on the SoC, he has a board that exposes "spi_0, spi_1, uart_0, uart_1, uart_2" and it is then direct: device_get_binding("UART_0"). One can relate it directly to the board.
Now it would require the user to know the controller, and the instance he needs, exposing then the instance concept to the user at the same time then... not sure it's wise.
Looks like I am in line with @erwango here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keeping the labels available under a default y kconfig would let users keep doing this for upstream samples but still let us get rid of the labels to save ROM when needed, agreed @tbursztyka ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When it comes to name, I think we want to get rid of them entirely. They are really useless.
(only maybe in debug mode, inside the actual driver, but nowhere else).
Instead we could generate BOARD_UART_0, BOARD_SPI_1, ... macros which in fact would hold the dev name (which is being build with the ZDID etc.. on this rfc). device_get_binding() would then call DEVICE_GET() with this, and since dts_device_extern.h already exposes the extern device pointers: done.
@galak That could be your solution to avoid fully deprecating device_get_binding(), though it would change it's signature (it would become a macro calling DEVICE_GET() macro).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I expect several device_get
APIs that would be new. We can continue to support device_get_binding()
via string. I'd expect we'd have:
device_get_by_dt_label(LABEL) [this is the node label, not the 'label' property]
device_get_by_dt_alias(ALIAS)
device_get_by_dt_path(PATH)
device_get_by_dt_inst(NAME, ID)
[not sure if this one is useful]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok sure, device_get_binding() would use device_get_by_dt_label then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
device_get_by_dt_inst(NAME, ID) [not sure if this one is useful]
If the NAME is type of the device and ID the index, then it would allow the same feature as suggested in #21709
This is prototype based on conversations at ELC-E 2019 on how we can make the device api be dt aware.
The idea here is that we'd use a unique identifier (Zephyr Device ID/ZDID) for each device tree node that would correspond to how we name the
struct device
for that device. We can then generate various DT defines likeDT_INST_0_SILABS_GECKO_I2C_ZDID
. These defines allow us to construct direct access to thestruct device
. This PR show changes to the silabs i2c gecko driver and a hacked up change to the i2c_scanner to show but the changes on the driver side (how aDEVICE_AND_API_INIT_DT
would look like, and howdevice_get_dt_binding
would work.There's at least one issue that needs to be figured out on how / where to do an
extern struct device __device_<ZDID>
.