-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Enabling PM for udc_mcux_ehci #90812
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
base: main
Are you sure you want to change the base?
Enabling PM for udc_mcux_ehci #90812
Conversation
4e46e52
to
146ddc5
Compare
drivers/usb/udc/udc_mcux_ehci.c
Outdated
data->vbus_present = vbus_present; | ||
|
||
/* | ||
* UDC will now unblock PM |
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.
What about USB suspend? VBUS is present but the device should enter as low power consumption as possible (with 2.5 mA suspend current limit for the whole device).
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.
@tmon-nordic, When USB suspend comes in what does the Zephyr USB stack do? Does it keep the USB enabled?
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.
USB suspend is entirely according to USB host. USB must be kept enabled and device must be able to resume within 10 ms.
Universal Serial Bus Specification Revision 2.0 9.2.6.2 Reset/Resume Recovery Time
After a port is reset or resumed, the USB System Software is expected to provide a “recovery” interval of
10 ms before the device attached to the port is expected to respond to data transfers. The device may ignore
any data transfers during the recovery interval.
After the end of the recovery interval (measured from the end of the reset or the end of the EOP at the end
of the resume signaling), the device must accept data transfers at any time.
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. Our current use case doesn't include this particular usage. But we are saving some internal information on a ticket if this use case does come up from our customers.
drivers/usb/udc/udc_mcux_ehci.c
Outdated
#if defined(CONFIG_PM_POLICY_DEVICE_CONSTRAINTS) | ||
pm_policy_device_power_lock_get(dev); | ||
#endif |
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.
No #if/#endif, that needs to be fixed in pm subsytem.
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.
@jfischer-no, do you want this author to change the underlying pm subsystem here with this PR?
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.
Fixed with PR #90938 please review :)
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.
No trivial overlays.
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.
How do we establish these nodes if they are not part of the core board/soc DTS?
static int udc_mcux_pm_action(const struct device *dev, enum pm_device_action action) | ||
{ | ||
struct udc_mcux_data *priv = udc_get_private(dev); | ||
|
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.
Apart from whether PM usage makes sense or not, it should be like
if (IS_ENABLED(CONFIG_PM)) {
return -ENOTSUP;
}
if not possible, then it should be fixed in PM subsytem.
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.
@jfischer-no This function needs to be wrapped with CONFIG_PM_DEVICE because of the way the PM macros work. At the bottom, PM_DEVICE_DT_INST_DEFINE() is setting things up IF the application has been defined for PM_DEVICE. If it hasn't, then the PM_DEVICE_DT_INST_DEFINE() is a null and to avoid "unused function" we need to wrap this overall function with the #if.
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.
This is what pm_device_driver_init is for, it allows you to reuse the pm hook implementations if PM_DEVICE is 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.
If it hasn't, then the PM_DEVICE_DT_INST_DEFINE() is a null and to avoid "unused function" we need to wrap this overall function with the #if.
No.
diff --git a/drivers/usb/udc/udc_mcux_ehci.c b/drivers/usb/udc/udc_mcux_ehci.c
index 1c8ddd12b58..5f0edc0b419 100644
--- a/drivers/usb/udc/udc_mcux_ehci.c
+++ b/drivers/usb/udc/udc_mcux_ehci.c
@@ -886,8 +886,7 @@ static int udc_mcux_driver_preinit(const struct device *dev)
return udc_mcux_init_common(dev);
}
-#ifdef CONFIG_PM_DEVICE
-static int udc_mcux_pm_action(const struct device *dev, enum pm_device_action action)
+static inline int udc_mcux_pm_action(const struct device *dev, enum pm_device_action action)
{
struct udc_mcux_data *priv = udc_get_private(dev);
@@ -909,7 +908,6 @@ static int udc_mcux_pm_action(const struct device *dev, enum pm_device_action ac
}
return 0;
}
-#endif /* CONFIG_PM_DEVICE */
static const struct udc_api udc_mcux_api = {
.device_speed = udc_mcux_device_speed,
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.
@jfischer-no No what? Use your words. You did not respond to the point that @dleach02 actually made. Are you claiming that what he said is not true?
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.
Statement "If it hasn't, then the PM_DEVICE_DT_INST_DEFINE() is a null and to avoid "unused function" we need to wrap this overall function with the #if."
is false.
Therefore my answer is 'No.', followed by a proof inside a diff that can be applied to the commit.
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.
This diff is not solving the issue "in spirit" :) making it inline
is like adding __maybe_unused
:) I will try to review the PR, though, I know nothing about USB, other than what it's shorthand for :)
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.
This diff is not solving the issue "in spirit" :) making it
inline
is like adding__maybe_unused
:)
And allow the compiler to optimize and discard it in a similar way to if (IS_ENABLED(CONFIG_PM)) {return ...}
. This is nothing new and is used in the project in many places.
@@ -525,10 +574,10 @@ usb_status_t USB_DeviceNotificationTrigger(void *handle, void *msg) | |||
case kUSB_DeviceNotifyLPMSleep: | |||
break; | |||
case kUSB_DeviceNotifyDetach: | |||
udc_submit_event(dev, UDC_EVT_VBUS_REMOVED, 0); | |||
udc_mcux_change_state(dev, priv->enabled, 0); |
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.
udc_submit_event(dev, UDC_EVT_VBUS_REMOVED, 0);
should be submitted here regardless of other states.
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.
If we do the change I suggested in change_state() then this would occur in that function.
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 did the change mentioned by @dleach02 on line 109
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.
break; | ||
case kUSB_DeviceNotifyAttach: | ||
udc_submit_event(dev, UDC_EVT_VBUS_READY, 0); | ||
udc_mcux_change_state(dev, priv->enabled, 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.
same as above
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.
In case github gets busy, the change in question is being addressed on line 109
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.
Same as above, not addressed.
drivers/usb/udc/udc_mcux_ehci.c
Outdated
data->vbus_present = true; | ||
|
||
/* | ||
* Block PM when usb is active. |
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.
Block PM from doing what? What is "usb is active"?
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.
Sorry for not being more clear, this was maybe a bad assumption on my part, but the only context this driver had from a usb interface point of view was rather the driver controller was enabled or if a VBUS signal is detected so I made the wrong assumption that this could only mean the controller is active, I have updated the comment.
drivers/usb/udc/udc_mcux_ehci.c
Outdated
@@ -92,6 +97,50 @@ static int udc_mcux_control(const struct device *dev, usb_device_control_type_t | |||
return 0; | |||
} | |||
|
|||
/* Helper function to keep track of the activity state for the udc */ | |||
static void udc_mcux_change_state(const struct device *dev, bool enabled, bool vbus_present) |
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.
static void udc_mcux_change_state(const struct device *dev, const bool enabled, const bool vbus_present)
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.
Understood, updated.
drivers/usb/udc/udc_mcux_ehci.c
Outdated
return; | ||
} | ||
|
||
if (vbus_present != data->vbus_present && enabled) { |
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.
That is wrong, must not depend on enabled, it is usually other way around.
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.
@jfischer-no this recipe came from the udc_smartbond driver (see usb_state_change() ). It has the same logic.
I'm guessing the UDC driver is only sending the VBUS_READY if the higher stack has already did the enable. What is the expected USB UDC stack handling of VBUS_READY/REMOVED in general? I can see that our original code sent this event without regard to enable state so is that the expected behavior of UDC drivers?
I think this condition should just remove the "enable". Then the logic would send the VBUS_READY/REMOVED only when there is a change here. It would also debounce the signal (not that I expect that to occur) such that we wouldn't send back to back READY or REMOVED.
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 unclear at the error but I have updated the conditional to be only based on the vbus_present variable.
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.
The author's goal for this patch is unclear.
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.
Sorry if this was unclear, my only goal is to support the current Power Management Hook that is presented in Zephyr, adding nxp usb as a PM_DEVICE when CONFIG_PM=y and supporting the pm_action callback api.
At the moment, this driver does not have enough context to reinit any lost context about the zephyr USB stack when waking up from STANDBY so the driver will only go into a lower power mode when in Standby.
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.
The point of the PR is to lock out the system power states that disable the USB peripheral when the USB is expected to be in use.
I think that eventually this should be handled by @bjarki-andreasen 's rework of PM from calling pm_device_runtime_get/put at the subsystem level, but for now we are trying to support the coherency of the "system managed device PM" paradigm that currently exists.
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.
The point of the PR is to lock out the system power states that disable the USB peripheral when the USB is expected to be in use.
It does not explain why this needs to be done in the driver rather than in the application, where application can determine the state of the USB device controller and set PM accordingly.
I think that eventually this should be handled by @bjarki-andreasen 's rework of PM from calling pm_device_runtime_get/put at the subsystem level, but for now we are trying to support the coherency of the "system managed device PM" paradigm that currently exists.
It looks like we should wait until the PM issue has been resolved. This does not prevent you from using this patch in your downstream repository, though.
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.
The point of the PR is to lock out the system power states that disable the USB peripheral when the USB is expected to be in use.
It does not explain why this needs to be done in the driver rather than in the application, where application can determine the state of the USB device controller and set PM accordingly.
Does it strictly need to be addressed by the driver, no, but also, the application doesn't strictly need to use a driver in the first place, does it? It doesn't need to even use the Zephyr ecosystem at all. It can just write bare metal code to control a USB without the stack, so why shouldn't it? So what is the problem with drivers being written robustly by contributing their knowledge to the system state?
I think that eventually this should be handled by @bjarki-andreasen 's rework of PM from calling pm_device_runtime_get/put at the subsystem level, but for now we are trying to support the coherency of the "system managed device PM" paradigm that currently exists.
It looks like we should wait until the PM issue has been resolved. This does not prevent you from using this patch in your downstream repository, though.
I don't agree that we either should or even need to wait. This code will be valid both before and after that PM reworking. What I said was that in my opinion, the subsystem level should contribute here, but I don't think that the driver can't also. Any component that has some information about the state of the system and the implications of that state, should utilize whichever mechanisms are available to it to contribute that knowledge to it's architectural connections.
Also, this fallback to "just use the patch in your downstream repository" is not a real thing. Nobody prefers to use a downstream repository. Everybody wants things in upstream releases. Maybe Nordic customers are used to it now, but it's not true universally.
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.
Ain't noone happy to be forced to some downstream that's for sure :)
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.
Does it strictly need to be addressed by the driver, no, but also, the application doesn't strictly need to use a driver in the first place, does it? It doesn't need to even use the Zephyr ecosystem at all. It can just write bare metal code to control a USB without the stack, so why shouldn't it? So what is the problem with drivers being written robustly by contributing their knowledge to the system state?
These changes are anything but robust. You have no idea how the UDC driver and USB device stack work, and you're just poking around. The UDC driver and the stack are already contributing all the bus states to the application. Only the USB application is aware of all the USB bus and USB device related states, such as battery charging. And as I said, the USB application should handle PM on its own in a generic way. Therefore, performing any PM on the driver level is pointless. Changes like these are not going anywhere in USB.
drivers/usb/udc/udc_mcux_ehci.c
Outdated
return udc_mcux_init_common(dev); | ||
} | ||
|
||
#ifdef CONFIG_PM |
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.
@EmilioCBen This needs to be CONFIG_PM_DEVICE to be complete. See
zephyr/include/zephyr/pm/device.h
Line 296 in 5cffb8e
#ifdef CONFIG_PM_DEVICE |
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.
Updated.
146ddc5
to
1d9a6df
Compare
Depends on 90938 |
@@ -525,10 +564,10 @@ usb_status_t USB_DeviceNotificationTrigger(void *handle, void *msg) | |||
case kUSB_DeviceNotifyLPMSleep: | |||
break; | |||
case kUSB_DeviceNotifyDetach: | |||
udc_submit_event(dev, UDC_EVT_VBUS_REMOVED, 0); | |||
udc_mcux_change_state(dev, priv->enabled, 0); |
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 may be in USB isr context, is it OK to call the pm
related functions 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.
I am unaware of the impact with PM and a device being in ISR.
I will state that it WILL be in ISR as these functions are only
called during the USB ISR. The device seems to work as intended
with or without PM from this PR, so nothing immediate sticks out
as a potential problem.
@@ -676,11 +715,19 @@ static int udc_mcux_set_address(const struct device *dev, const uint8_t addr) | |||
|
|||
static int udc_mcux_enable(const struct device *dev) | |||
{ | |||
struct udc_mcux_data *priv = udc_get_private(dev); | |||
|
|||
udc_mcux_change_state(dev, 1, priv->vbus_present); |
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.
udc_mcux_enable
may be called from application's tasks, and udc_mcux_change_state
is called from the USB isr too, I think protection is needed to make sure udc_mcux_change_state
is executed one by one and the enabled
and vbus_present
are updated rightly.
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 have made this variables volatile so they are only updated one at a time.
drivers/usb/udc/udc_mcux_ehci.c
Outdated
|
||
udc_mcux_get_hal_driver_id(priv, config); | ||
if (priv->controller_id == 0xFFu) { | ||
return -ENOMEM; |
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.
udc_mcux_init_common
has this part of codes too.
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.
Good catch, updated.
case PM_DEVICE_ACTION_TURN_OFF: | ||
break; | ||
case PM_DEVICE_ACTION_TURN_ON: | ||
udc_mcux_init_common(dev); |
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.
Just my concern from this part of codes: Why the PM_DEVICE_ACTION_TURN_OFF
doesn't need any codes? From the name of the ON
/OFF
, it seems that it is more matched with the controller functions udc_mcux_init
/udc_mcux_shutdown
. And I think it is dangerous that enable/disable controller function without going through the stack because the stack's states are mismatched with controller states.
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.
good point I can update the code to add udc_mcux_shutdown.
1d9a6df
to
641b3e0
Compare
e8a1deb
to
d8e1ab8
Compare
Enables PM support for USB devices that use udc_mcux_ehci. Signed-off-by: Emilio Benavente <[email protected]>
d8e1ab8
to
5e355ab
Compare
|
Removed DNM Label, dependent PR #90938 has merged. |
@jfischer-no please return to this PR and check if your review was addressed |
@@ -525,10 +574,10 @@ usb_status_t USB_DeviceNotificationTrigger(void *handle, void *msg) | |||
case kUSB_DeviceNotifyLPMSleep: | |||
break; | |||
case kUSB_DeviceNotifyDetach: | |||
udc_submit_event(dev, UDC_EVT_VBUS_REMOVED, 0); | |||
udc_mcux_change_state(dev, priv->enabled, 0); |
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.
break; | ||
case kUSB_DeviceNotifyAttach: | ||
udc_submit_event(dev, UDC_EVT_VBUS_READY, 0); | ||
udc_mcux_change_state(dev, priv->enabled, 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.
Same as above, not addressed.
volatile bool enabled; | ||
volatile bool vbus_present; |
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.
What is the intention behind using volatile
here? Is it an LLM suggestion? Are there any side effects that the compiler is not aware of?
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.
enabled
and vbus_present
are being used as atomics, accessed from multiple contexts, volatile
lets the compiler know that the value can be changed by another context at any time, so it has to be read every time its used, the compiler can't cache the value. For example:
volatile bool foo = false;
volatile bool bar = true;
if (foo) {
do_foo();
return;
}
/* ISR happens here and changes the value of foo to true */
/*
* compiler will "likely" not check foo again here, it will optimize out this branch entirely since
* since foo had to be false to get here, so foo && bar is not possible without volatile
*/
if (foo && bar) {
do_foobar()
}
without the volatile keyword, the compiler would not check foo again after the ISR, it will optimize the code to just check foo once, and never check bar :)
now, this should optimally be changed to using an atomic_t, but for archs where you know a reading bool is an atomic op, its not neccesary :)
/* | ||
* Copyright 2025 NXP | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
/ { | ||
chosen { | ||
zephyr,console = &cdc_acm_uart0; | ||
}; | ||
}; | ||
|
||
&zephyr_udc0 { | ||
cdc_acm_uart0: cdc_acm_uart0 { | ||
compatible = "zephyr,cdc-acm-uart"; | ||
}; | ||
}; |
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.
Again, no trivial overlays. This sample must not have any board overlays either.
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.
You have not answered the question asked to you above of how this is supposed to be done otherwise, since this configuration is specific to this sample. For this board, zephyr,console
is not normally this CDC ACM USB. What would you have the author do, specifically, besides remove the overlay, because that alone obviously does not align with the goal of the patch.
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.
How do we establish these nodes if they are not part of the core board/soc DTS?
Just as we have been doing for a long time. Have any of you thought about how this sample is used with other boards?
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.
Upon my inspection, it looks like, the sample uses DEVICE_DT_GET_ONE, instead of zephyr,console
, and uses a special nodelabel for how to define which node the cdc acm uart will go on with app.overlay . So @EmilioCBen you can make that change. However, @jfischer-no your comments are completely not helpful or collaborative. I am obviously not actually the one working on this PR but even if I was, I would be annoyed at how you are leaving vague riddles as reviews instead of just saying what you know that the author didn't and what exactly you want changed.
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.
Upon my inspection, it looks like, the sample uses DEVICE_DT_GET_ONE, instead of
zephyr,console
, and uses a special nodelabel for how to define which node the cdc acm uart will go on with app.overlay .
If you really inspected it, you would discover that it uses DEVICE_DT_GET(DT_CHOSEN())
const struct device *const dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); |
It is also obvious that you don't even need to look at the main.c, the overlay provides all the information you need.
However, @jfischer-no your comments are completely not helpful or collaborative. I am obviously not actually the one working on this PR but even if I was, I would be annoyed at how you are leaving vague riddles as reviews instead of just saying what you know that the author didn't and what exactly you want changed.
It is the responsibility of the PR author to familiarize themselves with the code they are changing. The same applies to colleagues passing by. It is irresponsible and reckless to poke around, waste other people's time, and expect everything to be explained. It is quite strange that none of you looked at the sample and saw that the app.overlay file contains the same content as the board overlay file, or questioned how that works for the other boards. So please hold back with your accusations, I do not accept them.
Finally, it is not too much to ask that people read the fancy manual
https://docs.zephyrproject.org/latest/build/dts/howtos.html#set-devicetree-overlays
https://docs.zephyrproject.org/latest/connectivity/usb/device/usb_device.html#console-over-cdc-acm-uart
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 see, I guess I looked at the old USB stack sample. Again, not working on the PR myself, but I am looking at this PR from an outside perspective and seeing your comments on it which are clearly not giving any indication of what you know that the PR author might have missed, that you are basically just making them play a game show to figure out what you mean. And I don't need to be an expert on USB or even know what a computer is to see when a person is not "playing nicely in the sandbox".
You might be a maintainer, but you seem to be mistaken in thinking that means you have a permit to be a jackass. In fact, you don't have less responsibility to stewarding the upstream, you have more. From being a maintainer, you become an assignee on PRs in your area, such as this one, which means that you are responsible to moderate this thread and resolve the disputes among the authors, maintainers (including yourself), and reviewers in order to avoid having to escalate. I don't see how you can be trusted to be moderating if you are the one causing the issues by intentionally making it a struggle to even understand what you are saying out of spite for when somebody makes a mistake in your eyes on their PR. That is just immature. https://docs.zephyrproject.org/latest/contribute/contributor_expectations.html
Either way. I agree with you to the extent that a PR author obviously should be responsible for making a good faith effort to properly know what they are doing when they make a PR submitting patches. However, that does not equate to meaning that everybody has to be perfect and omniscient or else F off and ignore them. At the end of the day, humans make mistakes, and don't know what they don't know they don't know. We aren't like the AI which you apparently so vehemently hate (although ironically, I suspect you would get along better with) which seem to have unlimited amounts of knowledge and time.
Lastly, simply just read https://docs.zephyrproject.org/latest/contribute/reviewer_expectations.html to understand that, regardless of your opinion, you have to follow these rules of what is expected of you if you are going to review PRs in the upstream. And I think you have either broken or neglected quite a few of them on this thread already.
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.
Just came here to echo, on behalf of the project's Code of Conduct team, what @decsny very articulately said in his comment just above. Please do try to keep your feedback and request for changes clear and actionable.
@@ -676,11 +716,19 @@ static int udc_mcux_set_address(const struct device *dev, const uint8_t addr) | |||
|
|||
static int udc_mcux_enable(const struct device *dev) | |||
{ | |||
struct udc_mcux_data *priv = udc_get_private(dev); | |||
|
|||
udc_mcux_change_state(dev, 1, priv->vbus_present); |
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.
udc_mcux_enable() should not emit UDC_EVT_VBUS_READY because there is no reason to do it at this point.
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.
The point of the way this is called is that udc_mcux_enable
is not trying to affect the state tracking of whether vbus is present. Explain how it could be, otherwise your comment here doesn't make sense to me.
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, some assumptions from my side:
- when udc_init, or any other udc API as called on this device, it must be able to detect power state of the bus, which means it must be ACTIVE from the perspective of device PM.
- Detecting power mode works in deeper sleep states than "operational" states
- Disabling states in devicetree refer to disabling operation currently, not vbus detection
Summarized solution:
add more sets of system states required for various operations of the hardware, and block these based on UDC API calls/UDC device state, don't rely on zephyr,disabling-states.
Proposed solution in steps:
- In the devicetree, update disabling states to only include states which prevent vbus detection
- Add a new, device driver specific set of system states to the devicetree (you are allowed to do that), call those op-disabling-states or something, and create your own set of
struct pm_state_constraint
to manually apply using pm_policy_state_lock_get from your driver as it is requested to be able to do something. - make udc_mcux_driver_preinit the init function of the device driver, call pm_device_driver_init() as the last call from the device driver init function
- Implement the following behavior in the udc_mcux_pm_action hook
- TURN_ON -> make sure device is in reset state
- RESUME -> do nothing here, udc_init() will be called at some point after RESUME, there you should block the states
which prevent vbus detection. - SUSPEND -> do nothing, udc_shutdown() should have been called before getting here.
- TURN_OFF -> make sure device is ready for being powered off
- now, what about the op-disabling system states? When udc_enable() is called for example, block the system states which would block the requirements of this UDC state, namely "Enable powered USB device controller and allow host to recognize and enumerate the device.", using pm_policy_state_lock_get(). unblock these sleep states again when udc_disable() is called, still blocking the sleep state which allows vbus detection
Naively and optimistically, that should be it :)
Last step would be for USB stack to call pm_device_runtime_get() on UDC device before calling udc_init() and put after calling udc_shutdown()
volatile bool enabled; | ||
volatile bool vbus_present; |
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.
enabled
and vbus_present
are being used as atomics, accessed from multiple contexts, volatile
lets the compiler know that the value can be changed by another context at any time, so it has to be read every time its used, the compiler can't cache the value. For example:
volatile bool foo = false;
volatile bool bar = true;
if (foo) {
do_foo();
return;
}
/* ISR happens here and changes the value of foo to true */
/*
* compiler will "likely" not check foo again here, it will optimize out this branch entirely since
* since foo had to be false to get here, so foo && bar is not possible without volatile
*/
if (foo && bar) {
do_foobar()
}
without the volatile keyword, the compiler would not check foo again after the ISR, it will optimize the code to just check foo once, and never check bar :)
now, this should optimally be changed to using an atomic_t, but for archs where you know a reading bool is an atomic op, its not neccesary :)
static int udc_mcux_driver_preinit(const struct device *dev) | ||
{ | ||
struct udc_data *data = dev->data; | ||
struct udc_mcux_data *priv = data->priv; | ||
|
||
k_mutex_init(&data->mutex); | ||
k_fifo_init(&priv->fifo); | ||
k_work_init(&priv->work, udc_mcux_work_handler); | ||
return udc_mcux_init_common(dev); | ||
} |
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.
preinit
here is what the device init function is supposed to do :)
@kartben Stop dismissing my reviews of the area I maintain! It is none of your business! |
Enables PM support for USB devices that use udc_mcux_ehci.